Aller au contenu principal

Partial reuse between Rails & JS, the easy way!

20/09/2011

Writing JavaScript code to display data retrieved from a JSON API can be easy and clean if you use templates.

If you don’t use JS templates and still manipulate the DOM of your page to fill in data from a JSON object, you’re just doing it wrong :).

There are lots of templating plugins available in JavaScript like jquery-tmpl, or even the template method from the great Underscore.js library.

But what is the easiest solution to reuse view partials between the Rails application and the JavaScript code? Often I have to display a partial statically in my view using a render call with some Ruby objects and render the same partial in JavaScript. I don’t want to maintain 2 versions of my partial.

After looking and testing many different solutions, one of the easiest is to use Mustache, a Rails gem plugin called Stache and ICanHaz.js.

Here is a Rails 3.1 example which provides a simple user partial.
This partial is used in the UsersController index action to display the first users.
Then it is reused in JavaScript in an AJAX pagination by fetching the next users in JSON.

In my Gemfile, we add :

gem 'jquery-rails'
gem 'will_paginate'

gem 'mustache'
gem 'stache'
# ...

Then I copy ICanHaz.js in assets/javascripts.

The UsersController is standard and responds to HTML and JSON…

class UsersController < ApplicationController
  respond_to :html, :json
  
  def index
    @users = User.page(params[:page])

    respond_with(@users)
  end

  def new
    @user = User.new
  end
end

Then we can write the user partial in Mustache (app/views/users/_user.html.mustache).

<div class="widget-user">
  <h3>User</h3>

  <p><strong>First name</strong> : {{ first_name }}</p>
  <p><strong>Last name</strong> : {{ last_name }}</p>
  <p><strong>Adress</strong> : {{ address }}</p>
  <p><strong>Zip code</strong> : {{ zip_code }}</p>
  <p><strong>Phone</strong> : {{ phone }}</p>
</div>

Remember that Mustache is a logic-less templating system, so you should not access complex objects with nested variables…

Thanks to the Stache gem, we can render this partial in our HAML (or Erb) view! (app/views/users/index.html.haml)

#users-list
  - @users.each do |user|
    = render "users/user", user.attributes.symbolize_keys

= button_tag "Load next >>", id: "duplicate-widget"

= template_include_tag "users/user"

When rendering the Mustache partial, we send it all the attributes of the user, so we don’t have to build a long Hash manually.
Notice the template_include_tag call. This helper is provided by Stache and directly puts the partial raw code in the view, so that we’ll be able to use it in JavaScript.

Next we’ll write the Load next button behavior in CoffeeScript which will fetch the next users then use the Mustache partial to render them.
Thanks to ICanHaz, we can render the user partial in just… one line of code!

window.page_number = 2

$(document).ready ->
  $("#duplicate-widget").click ->
    $.getJSON "/users.json?page=#{ window.page_number }", (users) ->
      window.page_number++
      $.each users, ->
        widget = ich.user_template(this) # render the user partial with the JSON object
        $("#users-list").append(widget)

    false
About these ads
Un commentaire

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

Suivre

Recevez les nouvelles publications par mail.

%d bloggers like this: