Skip to content

Commit

Permalink
Add live comments example
Browse files Browse the repository at this point in the history
  • Loading branch information
dhh committed Jul 11, 2015
1 parent 2a1e265 commit 2f347c8
Show file tree
Hide file tree
Showing 24 changed files with 173 additions and 10 deletions.
26 changes: 26 additions & 0 deletions app/assets/javascripts/channels/comments.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
App.comments = App.cable.subscriptions.create "CommentsChannel",
collection: -> $("[data-channel='comments']")

connected: ->
# FIXME: While we wait for cable subscriptions to always be finalized before sending messages
setTimeout =>
@followCurrentMessage()
@installPageChangeCallback()
, 1000

received: (data) ->
@collection().append(data.comment) unless @userIsCurrentUser(data.comment)

userIsCurrentUser: (comment) ->
$(comment).attr('data-user-id') is $('meta[name=current-user]').attr('id')

followCurrentMessage: ->
if messageId = @collection().data('message-id')
@perform 'follow', message_id: messageId
else
@perform 'unfollow'

installPageChangeCallback: ->
unless @installedPageChangeCallback
@installedPageChangeCallback = true
$(document).on 'page:change', -> App.comments.followCurrentMessage()
10 changes: 10 additions & 0 deletions app/channels/comments_channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CommentsChannel < ApplicationCable::Channel
def follow(data)
stop_all_streams
stream_from "messages:#{data['message_id'].to_i}:comments"
end

def unfollow
stop_all_streams
end
end
12 changes: 12 additions & 0 deletions app/controllers/comments_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CommentsController < ApplicationController
before_action :set_message

def create
@comment = Comment.create! content: params[:comment][:content], message: @message, user: @current_user
end

private
def set_message
@message = Message.find(params[:message_id])
end
end
6 changes: 6 additions & 0 deletions app/controllers/concerns/authentication.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
module Authentication
extend ActiveSupport::Concern

included do
before_action :ensure_authenticated_user
end

private
def ensure_authenticated_user
authenticate_user(cookies.signed[:user_id]) || redirect_to(new_session_url)
Expand Down
2 changes: 0 additions & 2 deletions app/controllers/examples_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
class ExamplesController < ApplicationController
before_action :ensure_authenticated_user

def index
end
end
9 changes: 9 additions & 0 deletions app/controllers/messages_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class MessagesController < ApplicationController
def index
@messages = Message.all
end

def show
@message = Message.find(params[:id])
end
end
2 changes: 2 additions & 0 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class SessionsController < ApplicationController
skip_before_action :ensure_authenticated_user, only: %i( new create )

def new
@users = User.all
end
Expand Down
6 changes: 6 additions & 0 deletions app/jobs/comment_relay_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class CommentRelayJob < ApplicationJob
def perform(comment)
ActionCable.server.broadcast "messages:#{comment.message_id}:comments",
comment: CommentsController.render(partial: 'comments/comment', locals: { comment: comment })
end
end
6 changes: 6 additions & 0 deletions app/models/comment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Comment < ActiveRecord::Base
belongs_to :message
belongs_to :user

after_commit { CommentRelayJob.perform_later(self) }
end
4 changes: 4 additions & 0 deletions app/models/message.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Message < ActiveRecord::Base
belongs_to :user
has_many :comments
end
2 changes: 2 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
class User < ActiveRecord::Base
has_many :messages
has_many :comments
end
4 changes: 4 additions & 0 deletions app/views/comments/_comment.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<article data-user-id="<%= comment.user.id %>">
<h3>Comment by <%= comment.user.name %></h3>
<p><%= comment.content %></p>
</article>
5 changes: 5 additions & 0 deletions app/views/comments/_comments.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<section id="comments" data-channel="comments" data-message-id="<%= message.id %>">
<%= render message.comments %>
</section>

<%= render 'comments/new', message: message %>
4 changes: 4 additions & 0 deletions app/views/comments/_new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<%= form_for [ message, Comment.new ], remote: true do |form| %>
<%= form.text_area :content, size: '100x20' %><br>
<%= form.submit 'Post comment' %>
<% end %>
2 changes: 2 additions & 0 deletions app/views/comments/create.js.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
$('#comments').append('<%=j render @comment %>');
$('#new_comment').replaceWith('<%=j render 'comments/new', message: @message %>');
8 changes: 5 additions & 3 deletions app/views/examples/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<h1>Action Cable Examples</h1>

<p>Hello <%= @current_user.name %> (<%= link_to 'Logout', session_url, method: :delete %>)!</p>
<p>
Hello <%= @current_user.name %>
(<%= link_to 'Logout', session_path, method: :delete %>)!
</p>

<p>
<ul>
<li>Appearance</li>
<li>Comments</li>
<li><%= link_to 'Messages with live comments', messages_path %></li>
</ul>
</p>
1 change: 1 addition & 0 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': true %>
<%= csrf_meta_tags %>
<meta name="current-user" id="<%= @current_user.try(:id) %>">
</head>
<body>

Expand Down
9 changes: 9 additions & 0 deletions app/views/messages/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<h1>Messages</h1>

<p>
<ul>
<% @messages.each do |message| %>
<li><%= link_to message.title, message %></li>
<% end %>
</ul>
</p>
5 changes: 5 additions & 0 deletions app/views/messages/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<h1><%= @message.title %></h1>

<p><%= @message.content %></p>

<%= render 'comments/comments', message: @message %>
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@
resource :session
resources :examples

resources :messages do
resources :comments
end

root 'examples#index'
end
12 changes: 12 additions & 0 deletions db/migrate/20150711101414_create_messages.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.references :user, index: true, foreign_key: true

t.string :title
t.text :content

t.timestamps
end
end
end
12 changes: 12 additions & 0 deletions db/migrate/20150711103112_create_comments.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.references :message, index: true, foreign_key: true
t.references :user, index: true, foreign_key: true

t.text :content

t.timestamps
end
end
end
21 changes: 20 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,26 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20150711093646) do
ActiveRecord::Schema.define(version: 20150711103112) do

create_table "comments", force: :cascade do |t|
t.integer "message_id"
t.integer "user_id"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["message_id"], name: "index_comments_on_message_id"
t.index ["user_id"], name: "index_comments_on_user_id"
end

create_table "messages", force: :cascade do |t|
t.integer "user_id"
t.string "title"
t.text "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_messages_on_user_id"
end

create_table "users", force: :cascade do |t|
t.string "name"
Expand Down
11 changes: 7 additions & 4 deletions db/seeds.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).

User.create! name: 'Funkmaster Flex'
User.create! name: 'The Notorious B.I.G.'
User.create! name: 'Snoop Dogg'
User.create! name: 'Ice Cube'
big = User.create! name: 'The Notorious B.I.G.'
snoop = User.create! name: 'Snoop Dogg'
flex = User.create! name: 'Funkmaster Flex'
ice = User.create! name: 'Ice Cube'

Message.create! title: 'Tha Shiznit', content: 'Poppin, stoppin, hoppin like a rabbit', user: snoop
Message.create! title: 'Hypnotize ', content: 'Hah, sicker than your average Poppa', user: big

0 comments on commit 2f347c8

Please sign in to comment.