Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for Switch tab issue #386

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ gem "coffee-rails"

# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem "jbuilder"
gem 'redis'

# bundle exec rake doc:rails generates the API under doc/api.
gem "sdoc", group: :doc
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ GEM
foreman
rails (>= 3.2)
rainbow (~> 2.1)
redis (3.3.0)
rspec-core (3.5.4)
rspec-support (~> 3.5.0)
rspec-expectations (3.5.0)
Expand Down Expand Up @@ -330,6 +331,7 @@ DEPENDENCIES
rails-html-sanitizer
rainbow
react_on_rails (~> 6.1)
redis
rspec-rails (~> 3)
rspec-retry
rubocop
Expand Down
4 changes: 4 additions & 0 deletions app/channels/application_cable/channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
4 changes: 4 additions & 0 deletions app/channels/application_cable/connection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module ApplicationCable
class Connection < ActionCable::Connection::Base
end
end
5 changes: 5 additions & 0 deletions app/channels/comments_channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class CommentsChannel < ApplicationCable::Channel
def subscribed
stream_from "comments"
end
end
2 changes: 2 additions & 0 deletions app/jobs/application_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class ApplicationJob < ActiveJob::Base
end
5 changes: 5 additions & 0 deletions app/jobs/comment_relay_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class CommentRelayJob < ApplicationJob
def perform(comment)
ActionCable.server.broadcast "comments", comment unless comment.destroyed?
end
end
4 changes: 2 additions & 2 deletions app/models/comment.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Comment < ActiveRecord::Base
validates_presence_of :author
validates_presence_of :text
validates :author, :text, presence: true
after_commit { CommentRelayJob.perform_later(self) }
end
1 change: 0 additions & 1 deletion app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
<body>

<%= react_component "NavigationBarApp" %>

<div class="container">
<%= yield %>
</div>
Expand Down
7 changes: 7 additions & 0 deletions client/app/bundles/comments/actions/commentsActionCreators.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ export function fetchCommentsFailure(error) {
};
}

export function messageReceived(comment) {
return {
type: actionTypes.MESSAGE_RECEIVED,
comment,
};
}

export function submitCommentSuccess(comment) {
return {
type: actionTypes.SUBMIT_COMMENT_SUCCESS,
Expand Down
34 changes: 31 additions & 3 deletions client/app/bundles/comments/components/CommentBox/CommentBox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import React, { PropTypes } from 'react';
import CommentForm from './CommentForm/CommentForm';
import CommentList, { CommentPropTypes } from './CommentList/CommentList';
import css from './CommentBox.scss';
import Immutable from 'immutable';
import ActionCable from 'actioncable';

export default class CommentBox extends BaseComponent {
static propTypes = {
Expand All @@ -19,14 +21,39 @@ export default class CommentBox extends BaseComponent {
}).isRequired,
};

constructor() {
super();
_.bindAll(this, [
'refreshComments',
]);
}

subscribeChannel() {
const { messageReceived } = this.props.actions;
const protocol = window.location.protocol === "https:" ? "wss://" : "ws://"
const cable = ActionCable.createConsumer(protocol+window.location.hostname+":"+window.location.port+"/cable");
cable.subscriptions.create({channel: "CommentsChannel"}, {
connected: () => {
console.log("connected")
},
disconnected: () => {
console.log("disconnected")
},
received: (comment) => {
messageReceived(Immutable.fromJS(comment));
}
});
}

componentDidMount() {
const { fetchComments } = this.props.actions;
fetchComments();
this.intervalId = setInterval(fetchComments, this.props.pollInterval);
this.subscribeChannel();
}

componentWillUnmount() {
clearInterval(this.intervalId);
refreshComments() {
const { fetchComments } = this.props.actions;
fetchComments();
}

render() {
Expand All @@ -43,6 +70,7 @@ export default class CommentBox extends BaseComponent {
<h2>
Comments {data.get('isFetching') && 'Loading...'}
</h2>
<a href="javascript:void(0)" onClick={this.refreshComments}>Refresh</a>
<p>
<b>Text</b> supports Github Flavored Markdown.
Comments older than 24 hours are deleted.<br />
Expand Down
1 change: 1 addition & 0 deletions client/app/bundles/comments/constants/commentsConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const FETCH_COMMENTS_FAILURE = 'FETCH_COMMENTS_FAILURE';

export const SUBMIT_COMMENT_SUCCESS = 'SUBMIT_COMMENT_SUCCESS';
export const SUBMIT_COMMENT_FAILURE = 'SUBMIT_COMMENT_FAILURE';
export const MESSAGE_RECEIVED = 'MESSAGE_RECEIVED';

export const SET_IS_FETCHING = 'SET_IS_FETCHING';
export const SET_IS_SAVING = 'SET_IS_SAVING';
10 changes: 10 additions & 0 deletions client/app/bundles/comments/reducers/commentsReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ export default function commentsReducer($$state = $$initialState, action = null)
});
}

case actionTypes.MESSAGE_RECEIVED: {
return $$state.withMutations(state => (
state
.updateIn(
['$$comments'],
$$comments => ($$comments.findIndex(com => com.get('id') === comment.get('id')) === -1 ? $$comments.unshift(Immutable.fromJS(comment)) : $$comments),
)
));
}

case actionTypes.SUBMIT_COMMENT_SUCCESS: {
return $$state.withMutations(state => (
state
Expand Down
5 changes: 5 additions & 0 deletions client/npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"lint": "eslint --ext .js,.jsx ."
},
"dependencies": {
"actioncable": "^5.0.1",
"autoprefixer": "^6.5.3",
"axios": "^0.15.2",
"babel": "^6.5.2",
Expand Down
1 change: 1 addition & 0 deletions client/webpack.client.base.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module.exports = {
// vendor-bundle.js. Note, if we added some library here, but don't use it in the
// app-bundle.js, then we just wasted a bunch of space.
'axios',
'actioncable',
'classnames',
'immutable',
'lodash',
Expand Down
1 change: 1 addition & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
config.action_cable.allowed_request_origins = [Rails.application.secrets.action_cable_url]
end
end
5 changes: 3 additions & 2 deletions config/cable.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Action Cable uses Redis by default to administer connections, channels, and sending/receiving messages over the WebSocket.
production:
adapter: redis
url: redis://localhost:6379/1
url: <%= ENV["REDISCLOUD_URL"] %>

development:
adapter: async
adapter: redis
url: redis://localhost:6379/1

test:
adapter: async
20 changes: 10 additions & 10 deletions config/database.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@
# database: db/production.sqlite3

# Uncomment below for a setup with just postgres and change your Gemfile to reflect this
default: &default
adapter: postgresql
username:
password:
default: &default
adapter: postgresql
username:
password:

development:
<<: *default
database: react_webpack_dev
development:
<<: *default
database: react_webpack_dev

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: react_webpack_test
test:
<<: *default
database: react_webpack_test

production:
<<: *default
Expand Down
1 change: 0 additions & 1 deletion config/environments/production.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@

# Action Cable endpoint configuration
# config.action_cable.url = 'wss://example.com/cable'
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]

# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@
get "react-router(/*all)", to: "pages#index"

resources :comments
mount ActionCable.server => "/cable"
end
3 changes: 3 additions & 0 deletions config/secrets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@

development:
secret_key_base: 231bf79489c63f8c8facd7bf27db1c2582a42a7f4302fccdb74ef35bc5dc91fb4e19dbf167f3003bdb4073818dfab4a9916890d193d535a7be458dbef1609800
action_cable_url : http://localhost:3000

test:
secret_key_base: 1ab8adbcf8410aebbce9b6dd6db7b5d090297bd22cf789b91ff44ae02711e8c128453d3e5c97eadf9066efe1a1e0dc1921faf7314d566c114d3ed60ae7ea614c
action_cable_url : http://localhost:3000

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
action_cable_url : <%= ENV["SERVER_PORT"] %>