Private Chat Room in Ruby on Rails 3.0

This sample will let you develop a private chatRoom using juggernaut. It push chats in realtime based on publish/subscribe model, hence making it extremely fast and scalable.

    Resources

Nodejs – http://nodejs.org/

Redis – http://code.google.com/p/redis/

Juggernaut – https://github.com/maccman/juggernaut/

JQuery – http://mirror.ozdiy.com/assets/b8/2f96a12bc919b37e09d303b86ea1b9_1251811910.html

    Getting started

1.  Install node-v0.2.5 – Download

2.  Install redis 2.0.4 – Download

3.  Run Redis server

./redis-server redis.conf

4.  Install juggernaut

git clone git://github.com/maccman/juggernaut.git --recursive
cd juggernaut
sudo node server.js

Till this point, you would have all things in place except that juggernaut would still not be able to publish chats onto channels. This feature will get enabled after Step#5

5.  Now you are ready to implement private chat app in RoR3. To get a sample chat application:

git clone git://github.com/prabgupt/chatclient.git --recursive
cd chatclient

6. To enable publishing by Juggernaut

sudo gem install juggernaut

7. run rails server

rails server

open URLS: localhost:3000/chat/channel1
localhost:3000/chat/channel2

channel1 and channel2 are assumed to be two users in this application who are trying to chat.

    In case you are interested to build your own app from scratch

Install jquery inside your application first before getting started


rails plugin install git://github.com/aaronchi/jrails.git

copy the javascript files in the plugin folder to your javascripts directory.

Develop two view html which will actually be chat windows for two different users say channel1 and channel2

Include javascripts library references

<%= javascript_include_tag 'jquery', 'application'%>

 

subscribe for private channel1_channel2 between users channel1 and channel2

	jug.subscribe("/chats/channel1_channel2", function(data){
		var li = $("<li/>");
		li.text(data);
		$("#mesg").append(li);
	});

 

Add ajax enabled form:

<div>&lt;% form_tag('/chat/send', :id =&gt; 'chat_window', :remote =&gt; true) do %&gt;
&lt;%= text_field_tag 'msg_body', '', :size =&gt; 50 %&gt;
&lt;%= text_field_tag 'sender', 'channel1'%&gt;
<div>&lt;%= submit_tag 'Send Message' %&gt;
&lt;% end %&gt;</div>
</div>

 

In the text_field_tag above sender can be choosen dynamically based on user if in session.

Add code inside controller associated with the view to publish message to server

#chat_controller.rb

require "juggernaut"class ChatController < ApplicationController

def send_message
@messg = params[:msg_body]
@sender = params[:sender]
Juggernaut.publish(select_channel("/channel1_channel2"), parse_chat_message(params[:msg_body], params[:sender]))
respond_to do |format|
format.js
end
end

...

Sub methods’ implementation are present inside code sample. You can anyways implement those in any way you like. Just keep in mind that juggernaut publish API requires channel name as first argument and second argument as message which is to be published to channel provided before. Here you can choose the channel dynamically based on users between whom message is currently being exchanged. Also you can write logic to persist messages, if you need, inside this method of controller.

Now final step would be to send_message.js.erb file with default name ‘send_message’ inside which we will reset the text fiend values

#send_message.js.erb
$("#chat_window")[0].reset();

 

You can perform various other operation here where in you can update only specific portion/fields of page depending on the user interface you choose for your chat window.

You are now ready to run this application. Please note that intend of current demo application is to just show how to build a private chat app using third party plugins in ruby on rails. You can anyways enhance it based on your usage.

I have listed below few issues which I faced while building this application which are applicable for any general applicatin being developed on ruby on rails 3.0

#1 : even after running ‘sudo gem install juggernaut’, it was showing following error at line: require “juggernaut”, which was present at top of application controller

	no such file to load -- juggernaut

 

Solution: On adding below line inside Gemfile of your project:

	gem 'juggernaut', :git =&gt; 'git://github.com/maccman/juggernaut.git'

 

and then running ‘sudo gem install juggernaut’, the issue was gone.

#2 : On running application, javascript console was throwing below error

jQuery is not defined

In my view html, I was calling jquery before application, however in default application layout call to default javascripts library was present which was mesing things up by calling application.js before jQuery was called.

Solution: Either change default javascript libraries setting or remove/change the call for the same inside application layout generated by default.

#3 : Error:

"Property '$' of object [object DOMWindow] is not a function" at line: $(document).ready(function()

 

Solution: This was coming because I was using jQuery in no conflict [jQuery.noConflict();]. After removing this mode, it worked fine. Though if you want to use jQuery mode in no conflict mode, which is btw recommended, you can check this thread: http://www.sitepoint.com/forums/showthread.php?t=712582

As per it, in “no-confict” mode, the $ shortcut is not available and the longer jQuery is used. To use the default jQuery shortcut of $, you can use the following wrapper around your code:

	jQuery(document).ready(function($) {
	    // $() will work as an alias for jQuery() inside of this function
	});

 

20 thoughts on “Private Chat Room in Ruby on Rails 3.0

  1. sorry,I got a bug on trying out this….
    I opened the URLS: localhost:3000/chat/channel1
    localhost:3000/chat/channel2
    and the page was OK.but after I entered messages and pressed the button, there are no chatting messages.Can you give me some advice?

    • Hey Bogeer,

      Sorry to reply late as somehow your comment was tagged as spam and I found it just now. Anyways, in case you still are facing this issue, it might be the case that publish command is not working for you. could you please check your server log or javascript console for any error and let me know. Also to track all the issues/updates, please follow https://github.com/prabgupt/chatclient

  2. Firefox won’t connect– Juggernaut directions are to add

    window.WEB_SOCKET_SWF_LOCATION = "http://juggaddress:8080/WebSocketMain.swf"

    But it’s still not updating for me. Works fine in Chrome with Websocket.

    • I didn’t try this workaround for firefox but copying WebSocketMain.swf from juggernaut installation to your rails app public folder did the trick. Let me know if you still faces this problem.

  3. Hi,

    Excellent example, thanks! I have been hunting around quite a bit, and yours is the first example that I was able to get working.

    I am trying to move the code into another app (same Rails and Ruby version–1.9.2, 3.0.3), but the chat controller in the second app processes the request as HTML instead of JS (and hence returns the “/chat/send” page, which is not what is wanted). Here is the entry from the working chat’s webrick log:

    Started POST “/chat/send” for 127.0.0.1 at 2011-02-21 15:35:19 -0600
    Processing by ChatController#send_message as JS
    Parameters: {“utf8″=>”✓”, “authenticity_token”=>”Bjy1QUYah8UaZ8cmGBO1KUYKEjn1MrZsAALcJdHO7sM=”, “msg_body”=>”hi”, “sender”=>”channel2”}
    Rendered chat/send_message.js.erb (0.4ms)
    Completed 200 OK in 30ms (Views: 28.5ms | ActiveRecord: 0.0ms)

    …and here is the one from the broken app:

    Started POST “/chat/send_message” for 127.0.0.1 at 2011-02-21 16:56:59 -0600
    Processing by ChatController#send_message as HTML
    Parameters: {“utf8″=>”✓”, “authenticity_token”=>”pqVLQv3YVyb45hVmyTdkapDXabVv99RO5wAaz6Pm3wg=”, “msg_body”=>”hi”, “sender”=>”channel2”, “commit”=>”Send Message”}
    Completed 406 Not Acceptable in 1ms

    I see two things fishy here: the “HTML” send, and the “Completed 406 Not Acceptable”. It feels like routing may be involved, but I’m not able to isolate the difference yet.

    Any ideas how to narrow down this issue?

    Thanks!
    -chris

    • Found it…the public/javascripts/application.js was slightly different:

      % diff chatclient/public/javascripts/application.js myapp/public/javascripts/application.js
      3,19d2
      < //jQuery.noConflict();
      <
      < jQuery.ajaxSetup({
      < 'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
      < })
      <
      < jQuery.fn.submitWithAjax = function() {
      < this.submit(function() {
      < $.post(this.action, $(this).serialize(), null, "script");
      < return false;
      < })
      < return this;
      < };
      <
      < $(document).ready(function() {
      < $("#chat_window").submitWithAjax();
      < })
      % cp chatclient/public/javascripts/application.js myapp/public/javascripts/application.js
      %

  4. I couldn’t only get things to work when I installed juggernaut using npm. Not sure whether that is true for everyone but might be worth calling out in the post.

    • Hey Kyrri,

      Yes Juggernaut has been updated recently and can now be installed using npm. I tried it myself and it worked well for me. You’ll now find installation steps different while rest of the things(usage etc.) remain the same.

Comments