Rails 5 tutorial: How to create a Chat with Action Cable

David Heinemeier Hansson recorded a screencast building a chat with Action Cable in Rails 5. Here we have a summary:

gem install rails -v 5.0.0.beta1

rails new chat --skip-spring

cd chat

rails g controller rooms show

rails g model message content:text

rails db:migrate

# app/controllers/rooms_controller.rb

class RoomsController < ApplicationController
  def show
    @messages = Message.all
  end
end

# app/views/rooms/show.html.erb

<h1>Chat room</h1>
 
<div id="messages">
  <%= render @messages %>
</div>
 
<form>
  <label>Say something:</label><br>
  <input type="text" data-behavior="room_speaker">
</form>

# app/view/messages/_message.html.erb

mkdir app/views/messages
<div class=“message”>
  <p><%= message.content %></p>
</div>

rails g channel room speak

# app/channels/room_channel.rb

class RoomChannel < ApplicationCable::Channel
  def subscribed
    stream_from "room_channel"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def speak(data)
    # ActionCable.server.broadcast "room_channel", message: data['message']
    Message.create! content: data['message']
  end
end

In order to turn on action cable on config/routes.rb we add:

mount ActionCable.server => '/cable'

And on app/assets/javascripts/cable.coffee we add:

@App ||= {}
App.cable = ActionCable.createConsumer()

# app/assets/javascripts/channels/room.coffee

App.room = App.cable.subscriptions.create "RoomChannel",
  connected: ->
    # Called when the subscription is ready for use on the server

  disconnected: ->
    # Called when the subscription has been terminated by the server

  received: (data) ->
    $('#messages').append data['message']
    # Called when there's incoming data on the websocket for this channel

  speak: (message) ->
    @perform 'speak', message: message

$(document).on 'keypress', '[data-behavior~=room_speaker]', (event) ->
  if event.keyCode is 13 # return = send
    App.room.speak event.target.value
    event.target.value = ""
    event.preventDefault()

# app/models/message.rb

class Message < ApplicationRecord
  after_create_commit { MessageBroadcastJob.perform_later self }
end

And finally we create app/jobs/message_broadcast_job.rb:

rails g job MessageBroadcast
class MessageBroadcastJob < ApplicationJob
  queue_as :default

  def perform(message)
    ActionCable.server.broadcast 'room_channel', message: render_message(message)
  end

  private
    def render_message(message)
      ApplicationController.renderer.render(partial: 'messages/message', locals: { message: message })
    end
end

The code is on GitHub: https://github.com/HectorPerez/chat-in-rails5

And the video of DHH:


4 Comments on “Rails 5 tutorial: How to create a Chat with Action Cable”

  1. keithpblog says:

    Hi, thanks for capturing this.
    Have you tried deploying this to AWS? Here is what we did but without success so far: https://keithpblog.wordpress.com/2015/12/30/rails-5-tutorial-chat-app-can-we-deploy-it/

    Like

  2. wuatanabe says:

    Hi Keith,
    I deployed the code on a single instance hosted on Cloud9 (not AWS).

    To have it working I had to add the following line in the config.ru file (in order to disable cross-site protection):

    ActionCable.server.config.disable_request_forgery_protection = true

    Kind Regards

    Paolo

    Like


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s