jQuery and Rails 3: A mini tutorial

Posted on   May 7th, 2010

As most of Rails developers, recently I’ve been through a process of unlearning all concepts of older versions of Rails and learning again the new ones of 3. But hey! I must admit that so far it’s been more pleasure than pain as things only get simpler and more natural than they used to be!

Here I’d like to talk about how simple it has become to integrate unobtrusive jQuery to a Rails app. Let’s use as an example a system of comments. I’ll create a simple app to create YouTube like comments:

Start typing in your teminal:

rails myCommentsApp
rails g resource Comment name:string body:text
rake db:migrate

Then we have to include the jQuery library and the jQuery driver file and place it inside /public/javascripts/ (or grab the helpers generator of Code Officer and do it automatically if you wish).  Now remove the  javascript_include_tag :defaults in the layout and add the following includes:
/app/views/layouts/application.html.erb

javascript_include_tag  "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"
javascript_include_tag  "http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"
javascript_include_tag "jquery-rails.js"

Now let’s add some logic to our program.  We’ll start out with an index action that will get all the comments:
/app/controllers/comments_controller.rb

def index
    @comments = Comment.all
    respond_to do |format|
      format.html # index.html.erb
      format.rss
    end
  end

And the views for the index will look like this:
/app/views/comments/index.html.erb

<span id="comments_count"><%= pluralize(@comments.count, "Comment") %></span>
<div id="comments">
  <%= render :partial => @comments, :locals => { :list => true } %>
</div>

<hr />

<div id="comment-notice"></div>

<h2>Say something!</h2>
<% form_for Comment.new, :remote => true do |f| %>
	<%= f.label :name, "Your name" %><br />
	<%= f.text_field :name %><br />
	<%= f.label :body, "Comment" %><br />
	<%= f.text_area :body, :rows => 8 %><br />
	<%= f.submit "Add comment" %>
<% end %>

Notice that the new attribute remote is all we need to worry about when creating a form that will submit with Ajax. Rails 3 works with HTML5 attributes, so it only adds the attribute data-remote=”true” to the form and that’s it, the jQuery driver will handle the rest.
We’ll create a partial for the comments:
/app/views/comments/_comment.html.erb

<%= div_for comment do %>
  <span class="dateandoptions">
    Posted <%=time_ago_in_words(comment.created_at)%> ago<br />
    <%= link_to 'Delete', comment_path(comment), :method => :delete, :class => "delete", :remote => true  %>
  </span>
	<p><b><%= comment.name %></b> wrote:</p>
	<br />
  <%= content_tag(:p, comment.body, :class => "comment-body") %>
<% end %>

So now let’s add the fireworks! That is, the asynchronous creation and deletion of comments along with some trendy effects. We come back to the CommentsController and add the actions:
/app/controllers/comments_controller.rb

 def create
    @comment = Comment.create!(params[:comment])
    flash[:notice] = "Thanks for commenting!"
    respond_to do |format|
      format.html { redirect_to comments_path }
      format.js
    end
  end

  def destroy
     @comment = Comment.find(params[:id])
     @comment.destroy
     respond_to do |format|
       format.html { redirect_to comments_path }
       format.js
     end
   end

And we are done with the logic part! A few javascript lines will end the work:
/app/views/comments/create.js.erb

/* Insert a notice between the last comment and the comment form */
$("#comment-notice").html('<div class="flash notice"><%= escape_javascript(flash.delete(:notice)) %></div>');

/* Replace the count of comments */
$("#comments_count").html("<%= pluralize(Comment.count, 'Comment') %>");

/* Add the new comment to the bottom of the comments list */
$("#comments").append("<%= escape_javascript(render(@comment)) %>");

/* Highlight the new comment */
$("#comment_<%= @comment.id %>").effect("highlight", {}, 3000);

/* Reset the comment form */
$("#new_comment")[0].reset();

/app/views/comments/destroy.js.erb

/* Eliminate the comment by fading it out */
$('#comment_<%= @comment.id %>').fadeOut();
/* Replace the count of comments */
$("#comments_count").html("<%= pluralize(Comment.count, 'Comentari') %>");

Finish! That’s all the effort you need nowadays to a create a Web 2.0 fashionable feature such as this one. Of course, you need some styling with CSS, and you would need tons of more things in the real world (such as antispam, authentication, something to comment about…) but that’s the part I chose to talk about today!

I pushed myCommentsApp to Github in case you want to have a closer look (or download the zip version).

You might be interested in checking out my script for letting user in-place edit your application contents.

Tags:

60 Comments »

60 Comments on “jQuery and Rails 3: A mini tutorial”

Follow comments feed

Jordi said at 2:52 pm on May 8th, 2010:

Wow that code looks familiar to me!

That’s a very useful code, I think every comment system should be like this by now, people is getting used to it and feels weird the get the old school redirect.

Also, this code is perfectly compatible with Rails 2, except in rails 2 you don’t need the “jquery rails driver” but the jrails plugin, and instead of using form_for with the :remote => true you should use remote_form_for.

PS: The textarea for submitting comments (in your blog, no the example app) has way too big font size! I have like 4 words per line XD

PS2: I like the new imperative to attract people to comment…

Bernat said at 7:13 pm on May 8th, 2010:

Of course it is familiar to you dude, I coded it first for our joint project semantic.cat (http://github.com/bernat/semantic) and copy&pasted after to my blog, so as to be useful to someone else (which may not be the case).

Indeed, the way you code Ajax actions now and before hasn’t changed that much apparently, though it has in the inside. Taking profit of HTML5 attributes now there’s no need to add blocks of javascript code mixed with markup, you redefine everything separately in your “driver”. In fact, you can capture more actions defining new remote handlers almost painlessly, creating as “data-” attributes as you wish.

You’re right about the font-size being too big, I’ll have it change… someday!

Rails 3 upgrade part 4: Prototype helpers and Javascript at MetaGreg said at 3:44 am on August 25th, 2010:

[...] equivalent for Prototype helper plugin yet so that would be an issue like in my case. Based on this jQuery and Rails 3 tutorial, using the jQuery UJS driver looks very [...]

Cristian said at 1:18 am on September 9th, 2010:

Thanks, it has been really useful for me.

Juba said at 2:02 pm on September 14th, 2010:

Wow, thanks ! This tutorial was exactly what I was looking for. Now I think I even understand the use of .js.erb files !

v said at 6:21 pm on September 17th, 2010:

tes

Cipe said at 11:05 am on September 19th, 2010:

Hi dude! That’s great

Blake said at 6:51 pm on September 24th, 2010:

Cheers for the tutorial… helped me get a few cool things working :)

Flunder said at 12:59 am on September 26th, 2010:

Thanks alot! This was very handy, thanks for putting it up!

chrismealy said at 2:17 am on September 27th, 2010:

Thanks for the tutorial. It was exactly what I needed. Even better, your code on github worked with zero trouble.

Rails 3 upgrade part 4: Prototype helpers and Javascript « Philippine Ruby Users Group said at 4:36 am on September 27th, 2010:

[...] equivalent for Prototype helper plugin yet so that would be an issue like in my case. Based on this jQuery and Rails 3 tutorial, using the jQuery UJS driver looks very [...]

Fabio said at 1:36 am on October 1st, 2010:

Thanks for the article, very useful…

Moshe said at 10:53 am on October 2nd, 2010:

I found an issue with this method of using jquery – escape_javascript removes javascript from the partial. What happens if you need javascript in the partial? for example for autocomplete?

Puneet Pandey said at 11:21 am on October 15th, 2010:

Thanks for sharing this quick tutorial… its very helpful.

Regards
Puneet

bernat said at 11:59 am on October 15th, 2010:

Hey Moshe, excuse me I did not see your reply. This was just the simplest of all possible ways to do it but of course you don’t have to escape javascript, once you’ve got the @comment you can display it the way you like and use all the power of jQuery. If you give me a specific example I can try to help.

Sunny said at 11:51 am on October 16th, 2010:

Hi thanks for the guide, helped me a lot. One thing I don’t understand is how the flash message is shown
“flash.delete(:notice)” this part especially seems strange because of the delete word when we’re trying to show it.

bernat said at 12:14 pm on October 16th, 2010:

Hello Sunny,
when you display a flash notice you want to do both things at a time: One is to actually display it and the other is to clear it out so it won’t show up at the next request. With flash.delete[:notice] we do both.

zegal said at 5:13 pm on October 18th, 2010:

nice, thanks.

Thimo said at 1:14 pm on October 25th, 2010:

Hi, thanks for that very nice tutorial :) But I have a
problem ;) I have exectly the same code and it works all fine
expect of the all the things in the create.js.erb :-/ There is no
highlighting or notice… I use Mozilla Firefox 3.6.11 I got the
following failure in the failure console of firefox: Fehler:
uncaught exception: [Exception... "Cannot modify properties of a
WrappedNative" nsresult: "0x80570034
(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN)" location: "JS frame ::
chrome://global/content/bindings/autocomplete.xml ::
onxblpopuphiding :: line 825" data: no] Is there any other way to
get your nice result without that exception?

coda said at 9:28 pm on October 28th, 2010:

yaaaayyy! awesome

Doug said at 1:07 am on November 3rd, 2010:

This is great, awesome, woo yeah!

Lyadon said at 11:48 pm on November 8th, 2010:

something!!!

fernando said at 10:07 pm on November 9th, 2010:

uahuuuuu !!!

jordan said at 10:32 am on November 20th, 2010:

awesome

Javix said at 9:09 am on December 8th, 2010:

Nice tutorial. Some improvements are needed nevertheless:
- add validations for a comment(no empty comment body or comment name)
- flash notice need to be fade out after deleting a comment, for example like that:

$(‘.flash.notice’).fadeOut(); #in destroy.js.erb

Jakko said at 11:44 pm on December 12th, 2010:

Great stuff!

Pancho said at 4:20 pm on December 19th, 2010:

Fantastic tutorial! It’s been really useful :)

Alejandro said at 2:48 pm on December 29th, 2010:

Hi,
i have some prblems. all code works fine, but, if i have a “format.html” on respod_to and in template a button_to with :remote => true, the format.js dont respond, always shows the format.html unless i comment that line.

how can i fix that? maybe i doing something wrong.

thanks.

bernat said at 2:59 pm on December 29th, 2010:

I’m not sure I understand your problem. If you add a :remote => true in your template AND you have the jQuery driver for Rails Helpers added in your layout, you should be able to catch a JS request by adding the format.js line in the respond_to block. If it goes to format.html, as you say, it’s because you are doing a regular synchronous request. Probably not have the jquery.rails.js. If you do a JS (AJAX) request you will only notice what happens by looking at your server console.

Pizzicatto said at 4:33 pm on January 13th, 2011:

THanx, man.. good mini-tutorial! :)

josh said at 1:38 am on January 18th, 2011:

good one

Ryan said at 1:24 am on January 27th, 2011:

Thank you. Very informative.

Markus said at 2:12 pm on February 8th, 2011:

> As most of Rails developers, recently I’ve been through a
> process of unlearning all concepts of older versions of Rails
> and learning again the new ones of 3.

Is there a good starting point to learn the concepts? I tried to find something, but not sure yet.

I have also tried to run your application. But it doesn’t work. Once I have submitted the form it stops with an error message. However, the record is stored in the database. Do I have to install or copy any js libaries before running the application?

Markus said at 9:11 pm on February 8th, 2011:

I just tried again with the zip-file. After extracting, I did:

bundle install
rake db:migrate
rails s

In the browser I add a comment and pressed the submit button. Nothing happened in the browser and in the console I got the following error message.

http://bit.ly/dYHJg7

Any ideas?

Josh said at 9:59 pm on February 14th, 2011:

Wow this is very nice!

Bijesh said at 9:53 pm on February 21st, 2011:

This is nice tutorial. Facing problem in one case. After AJAX request, I want to redirect_to different page instead of updating RESPONSE in any div, how can we do this ?

zlorfi said at 1:38 pm on February 24th, 2011:

Hi,

it seems your
$(“#new_comment”)[0].reset();
doesn’t reset the comment form, nor does
$(“#new_comment”).get(0).reset();
seem to help :/
The rest seems to work.

paul said at 1:13 am on February 27th, 2011:

Thanks for writing this blog entry, everything worked great. I’m unclear about the following statement:

render :partial => @comments, :locals => { :list => true }

I cannot seem to find out where the locals :list is being referenced. Where should I be looking? I poked around the ‘render’ documentation and also div_for and contact_tag_for and was unable to understand how that symbol is being used.

Thanks again!

Tenshi said at 1:02 pm on February 28th, 2011:

Nice!

Kleber said at 2:21 pm on February 28th, 2011:

Hi paul,

As I understand, rails will look for a file called _comments under your comments folder in your views, and in this file (_comments.html.erb) you should be able to access the comment variable as a list.

So, this way, you don’t have to do an “for” to generate it.

Hope it helps anyway.

Luiz said at 9:27 pm on March 13th, 2011:

Thanks for the nice tutorial

vignesh said at 9:32 am on March 14th, 2011:

Thanks for this tutorial….It helped me a lot in developing my own rails app :)

Mack said at 9:05 pm on March 23rd, 2011:

This is awesome tutorial!

Chip said at 2:16 am on April 4th, 2011:

Fantastic. Very well done — I searched high and low for something as clear and straightforward as this. I was able to quickly move forward on a project I’ve been working on, and had hit a roadblock. Thank you!

Sathish said at 10:08 pm on April 7th, 2011:

I like it your post because i implemented that on my project but i try to add email for gravatar photo will appear in the comment .. it says error how to do it..
Thanks in advances

Rachid said at 12:02 pm on April 8th, 2011:

Well done! but why did you not put -J in the first rails calls, that would spare you deleting files ;-)

najob said at 5:36 pm on April 12th, 2011:

Hi, love the tutorial and the commenting system is very nice.

Mamoun said at 1:55 pm on April 27th, 2011:

I love you man thanks a bunch from a junior rails developer :)

Carlo said at 10:30 am on April 28th, 2011:

Man there is an error:
Missing template comments/create with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:html], :locale=>[:en, :en]} in view paths “/home/carlo/Desktop/myCommentApp/app/views”

Dan said at 2:41 pm on May 26th, 2011:

Hi, I like your tutorial. Short and sweet. I have a question. I am trying to create a http link that will invoke a form submit via ajax. How can I do it?

rubylicious said at 7:08 am on June 29th, 2011:

Nicely done sir!

fearless fool said at 5:14 am on July 13th, 2011:

This was a great help — thanks. BTW, a slightly cleaner way to include jQuery in your app:

[1] add the line gem 'jquery-rails' to your Gemfile
[2] execute bundle install on the command line
[3] execute rails generate jquery:install on the command line

That will remove the unused prototype code, install jQuery and jquery_ujs. Now you can leave the original javascript_include_tag :defaults in views/layouts/application.html.erb.

fearless fool said at 10:23 pm on July 13th, 2011:

@bernat: I liked your example so much that I made a fork of myCommentsApp and tweaked it to use the latest Rails with postgresql with README instructions on how to deploy it on Heroku. See github link above.

edmond said at 9:12 am on August 1st, 2011:

thanks a lot.

Cory Logan said at 10:31 am on August 14th, 2011:

I really appreciate the simplicity of the tutorial. I still have not yet digested all of it, but it’s in a wonderful bite sized chunk. Thanks!

Guru Prasad said at 8:35 am on August 23rd, 2011:

Nice tutorial.
Thanks a lot :)

~gurufrequent

Pat Shaughnesy said at 4:29 pm on August 26th, 2011:

Thanks a lot, Bernat – this was very helpful for me too… nice job writing: just enough info but not more.

Rick said at 4:31 am on September 4th, 2011:

Thanks for the tutorial.

I’m really new to Ruby on Rails, but I was curious. How could the Web page “invoke” the functionality of a form submission, in order to activate Javascript/JQuery code?

Perhaps this is a fundamental axiom with this framework, but I’m very green to RoR.

I currently have Ruby 1.8.7 and Rails 3.0.9. I’ve also installed the “jquery-rails” gem, whereby my application uses JQuery for its Javascript library, rather than Prototype. How would I update information, dynamically, “after” a page loads?

I’m trying to fetch info from another site for an area of a page, after it’s loaded. I don’t want the user to wait for the entire page to load, because the page is waiting for one DIV’s content to render.

Would anyone have any feedback on that? I’ve thought of doing the work you outline in this tutorial, but I don’t want to have to force a user to click on a form link on my page, in order to do that.

Any feedback would be GREATLY appreciated. Thanks in advance RoR community!!

Mark William said at 12:56 pm on November 3rd, 2011:

Thank you so much for the tutorial.
i liked it very much.
Thank you for sharing.

saurabh udaniya said at 6:50 am on December 2nd, 2011:

this is the best lesson of ajax thanks a lot



Say something!


Powered by WP Hashcash