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><% form_tag('/chat/send', :id => 'chat_window', :remote => true) do %> <%= text_field_tag 'msg_body', '', :size => 50 %> <%= text_field_tag 'sender', 'channel1'%> <div><%= submit_tag 'Send Message' %> <% end %></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 => '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 });
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
messages sent by other browsers not display in Opera browser but messages can send.
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.
another solution of no such file to load — juggernaut is
rails plugin install git://github.com/maccman/juggernaut_plugin.git
you should not be using juggenaut_plugin as it is old juggernaut and doesn’t use redis / node and hence not scalable. Juggernaut 2(https://github.com/maccman/juggernaut) is the latest juggernaut version which is completely re-written and uses node/redis.
how to fix this error?
NoMethodError (undefined method `publish’ for Juggernaut:Module):
app/controllers/chats_controller.rb:7:in `send_message’
What version of redis are you using?
Please try ‘which redis’ in unix console to check which version is being exactly used. You should be using 2.x version of the redis, perhaps its latest stable version, the one mentioned in this blog.
redis version is 2.2.0-rc3.
but ‘which redis’ is nothing.
You seems to be using juggernaut_plugin, older version which doesn’t use redis/node and that is the reason publish method is undefined in Juggernaut because it has been introduced since latest version of Juggernaut(https://github.com/maccman/juggernaut)
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
%
Hmmm, actually it was *all the way* different! The application.js file in myapp’s directory was empty. Doh.
Thank you yaar..
I was finding solution of same problem from long days.
Thanks again
Hi chat working fine between Chrome & Mozilla but in Opera browser send messages but not receive/display on chat window ….
I am surprised….
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.
Well, nice!
Found you here finally. Let’s me try it now.
Thanks,