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 »