Chat Implementation in Rails Using Private_pub

Private Pub is a Ruby gem which uses Faye to publish and subscribe to messages. For installing just add this to Gemfile of rails application and run Bundle install.

╰─$ rails new chat_private_pub/
╰─$ cd chat_private_pub/
╰─$ echo "2.1.1" >> .ruby-version (optional)
╰─$ echo "chat_private_pub" >> .ruby-gemset (optional)
╰─$ echo "gem 'private_pub'" >> Gemfile (adds gem private_pub to Gemfile)
╰─$ echo "gem 'thin'" >> Gemfile (adds gem thin to Gemfile)
╰─$ rails g scaffold Message content (just to create basic CRUD operations for messaging)
╰─$ rake db:create db:migrate
╰─$ rails g private_pub:install
╰─$ rails s
╰─$ rackup private_pub.ru -s thin -E production (in another tab)

This completes the basic installation. Last command generates two file, one of which is config/private_pub.yml. This stores the configuration for the connection with faye server. Next is add private_pub.js to application.js

//= require private_pub

Do the follwoing changes in files and make them look like

messages/index.html.erb

messages/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
<h1>Messages</h1>

<div id='chat'>
  <% @messages.each do |message| %>
      <%= render 'messages/message', message: message  %>
  <% end %>
</div>

<%= render 'messages/form' %>


<%= subscribe_to "/messages/new" %>

messages/_form.html.erb

messages/_form.html.erb
1
2
3
4
5
6
7
8
9
<%= form_for @message, remote: true do |f| %>
  <div class="field">
    <%= f.label :content %><br>
    <%= f.text_field :content %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

messages/messages_controller.rb

messages_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MessagesController < ApplicationController
  before_action :set_message, only: [:show, :edit, :update, :destroy]

  def index
    @messages = Message.all
    @message = Message.new
  end

  ....
  ....

  def create
    @message = Message.new(message_params)
    respond_to do |format|
      format.js
    end
  end

  ....
  ....

end

Create a new file messages/create.js.rb messages/create.js.erb

messages/create.js.erb
1
2
3
<% publish_to "/messages/new" do %>
  $("#chat").append("<%= j render('messages/message', message: @message) %>");
<% end %>

The magic happening here is by :

<%= subscribe_to "/messages/new" %>

<% publish_to "/messages/new" do %>
    $("#chat").append("<%= j render(@messages) %>");
<% end %>

subscribe_to is subscribing to listen to a particular channel, and publish_to is publishing to that channel. So, when we publish on the channel it is received at subscriber and the action is performed.

For more detail check Private Pub and Railcast. Source code can be found here.

Comments