Integrating Jade Templates into Rails for Cleaner Templates

Share this article

jade

Rendering dynamic content in a web application can be done using many tools, one of them is using a Javascript Template Engine. It uses a language with specific markup designed to render dynamic content to the Document Object Model.

Most of the markup used by javascript template engines resembles HTML, but some go further by introducing a new markup designed with a specific goal in mind. Jade has a unique characteristic compared to other javascript template languages. It simplifies the markup by removing the use of angle brackets and closing tags.

In this article, I will be demonstrating how to integrate Jade into a Ruby on Rails application. As an example, the application will be twitter-like, including timeline and user profile features to demonstrate the integration.

Some code examples in this article are taken from the example application, and some are simplified code taken from the code example. The completed version is available at Github, and there is also an online version available to demonstrate how it looks.

Introduction to Jade

Let me start by introducing you to the basics of Jade. After reading this section, you should be able to understand the basic construct of Jade. This, however, does not try to replicate the Jade documentation. Instead, I will highlight the most frequently used features in Jade so that you can get up and running fast.

It’s always good to start with what you know. Here is a comparison between ERB (Embedded Ruby), Jade, and the generated HTML. The following code is taken from the completed version of my tweet template implementation. A quick glance at the following code should be able to give you a glimpse of how Jade differs from ERB:

ERB

<li class="tweet">
  <%= link_to tweet.user do %>
    <img src="<%= tweet.user.thumbnail %>" class="tweet__photo" />
  <% end %>
  <div class="tweet__body">
    <div class="tweet__info">
      <%= link_to tweet.user.name, tweet.user, class: "tweet__name" %>
      <%= link_to "@#{tweet.user.username}", tweet.user, class: "tweet__username" %>
      <span class="tweet__date timeago" title="<%= tweet.created_at.iso8601 %>"></span>
    </div>
    <div class="tweet__text"><%= tweet.text %></div>
  </div>
</li>

Jade

li.tweet
  a(href=tweet.user.links.self)
    img.tweet__photo(src=tweet.user.thumbnail)
  .tweet__body
    .tweet__info
      a.tweet__name(href=tweet.user.links.self)=tweet.user.name
      a.tweet__username(href=tweet.user.links.self) @#{tweet.user.username}
      span.tweet__date.timeago(title=tweet.created_at)
    .tweet__text=tweet.text

Generated HTML

<li class="tweet">
  <a href="/@johnappleseed">
    <img class="tweet__photo" src="/path/to/image.jpg">
  </a>
  <div class="tweet__body">
    <div class="tweet__info">
      <a class="tweet__name" href="/@johnappleseed">John Appleseed</a>
      <a class="tweet__username" href="/@johnappleseed">@johnappleseed</a>
      <span class="tweet__date timeago" title="2015-11-30t01:30:10z"></span>
    </div>
    <div class="tweet__text">The quick brown fox jumps over the lazy dog</div>
  </div>
</li>

A look at the above code shows a distinct difference between Jade and ERB. Jade looks simpler and cleaner than ERB. This is due to the absence of closing tags and angle brackets in Jade.

Tag Name, ID, Class, and Attributes

From the previous template example, you can see that Jade uses tag name, ID, and CSS literals to create the DOM structure. Attributes are similar to those in HTML, but their values are just regular javascript. And because divs are the most common choice of tag, it is the default tag if you skip the tag name.

The following code:

li.tweet#tweet(title="tweet")
  .tweet__body

Will render to:

<li id="tweet" class="tweet" title="tweet">
  <div class="tweet__body"></div>
</li>

Buffering and Interpolation

Inside the template you can do all sorts of javascript operations, such as buffering code to be written to the template and interpolating strings. Consider the following example. Let’s assume you pass the tweet object with the following structure:

var tweet = {
  text: "The quick brown fox jumps over the lazy dog",
  user: {
    name: "John Appleseed",
    username: "johnappleseed",
    thumbnail: "/path/to/image.jpg",
    links: {
      self: "/@johnappleseed"
    }
  }
};

You can generate a link to a user as follows:

a.tweet__name(href=tweet.user.links.self)=tweet.user.name

The above will generate the following HTML:

<a class="tweet__name" href="/@johnappleseed">John Appleseed</a>

If you want to interpolate a string, you can use the familiar #{} operator:

a.tweet__username(href=tweet.user.links.self) @#{tweet.user.username}

And it will render the following HTML.

<a class="tweet__username" href="/@johnappleseed">@johnappleseed</a>

The Integration

Integrating Jade into Rails requires a handful of steps. The installation steps are pretty straightforward, but as of this writing, there is a compatibility issue with the latest version of Rails. There is a workaround for this issue, please see the installation instructions for more detailed information.

Installation

To have a working installation of Jade in a Rails application, please put the following gems into your Gemfile:

# Gemfile
gem 'ejs'
gem 'jade-rails', '1.9.2'

And require Jade runtime into your application.js:

# app/views/assets/javascripts/application.js
//= require jade/runtime

As noted previously, as of this writing, there is a template compilation issue for Rails version 4.2.5. Please replace the jade-rails gem with my github branch:

# Gemfile
gem 'jade-rails', github: 'hendrauzia/jade-rails', branch: 'rails-4-2-5'

As a side note, the above source as of this writing haven’t been merged into jade-rails gem, but in the future this may have been rectified. Please consult the jade-rails releases to see if the fix has been applied.

Templates

Templates must be put in a specific place in your application. You need to put them inside app/assets/javascripts/templates, and give them the .jst.jade extension. You can also add another preprocessor to your templates, such as: .erb if necessary.

See the following example:

# app/assets/javascripts/templates/tweet.jst.jade
li.tweet
  ...

Here is a small tip if you need to put image assets in the template: Add ERB to your template preprocessor and add the .erb extension to the end of the template name. This Way, the assets can be rendered using the proper digest. For example, you might want to provide a default image when a user doesn’t have a picture:

# app/assets/javascripts/templates/tweet.jst.jade.erb
li.tweet
  a(href=tweet.user.links.self)
    if tweet.user.thumbnail
      img.tweet__photo(src=tweet.user.thumbnail)
    else
      <%= image_tag "users/default.jpg", class: "tweet__photo" %>

And don’t forget to require your template in your application.js:

# app/assets/javascripts/application.js
//= require templates/tweet

The rest of the template features can be found in the Jade documentation. But before you decide on doing any fancy stuff, please read the remainder of my introduction.

Rendering

The template rendering capability in Jade is provided by the ejs gem. To render the template, use the following statement and put it in your javascript file. Using our previous example, if we want to render the template, we need a tweet object to pass into the template rendering function:

var tweet = {
  text: "The quick brown fox jumps over the lazy dog",
  user: {
    name: "John Appleseed",
    username: "johnappleseed",
    thumbnail: "/path/to/image.jpg",
    links: {
      self: "/@johnappleseed"
    }
  }
};

var htmlString = JST['templates/tweet']({ tweet: tweet });

The above code will generate the following HTML:

<li class="tweet">
  <a href="/@johnappleseed">
    <img src="/path/to/image.jpg" class="tweet__photo">
  </a>
  <div class="tweet__body">
    <div class="tweet__info">
      <a class="tweet__name" href="/@johnappleseed">john appleseed</a>
      <a class="tweet__username" href="/@johnappleseed">@johnappleseed</a>
      <span class="tweet__date timeago" title="2015-11-30t01:30:10z"></span>
    </div>
    <div class="tweet__text">the quick brown fox jumps over the lazy dog</div>
  </div>
</li>

If you need further customization, like attaching event listeners to DOM or otherwise messing with the DOM prior to appending to a container, you can create a jQuery object from the DOM and preprocess it.

For example, here we try to attach timeago to the tweet date:

var htmlDOM = $(JST['templates/tweet']({ tweet: tweet }));
htmlDOM.find(".timeago").timeago();

Once everything is set and done, you can append the rendered HTML to any container that you want. In this case, let’s say we want to put at the end of the timeline:

$('.timeline').append(htmlDOM);

Limitations

Integrating Jade in Rails is not without its limitations. There are features in jade that are not available in the client. For example, includes and extends are not available in the current stable jade-rails gem. As a workaround, you can manually appending the generated HTML to other generated HTML using javascript.

Conclusion

Jade is a simple and clean javascript template engine. It can be integrated easily to a Rails application and works nicely with the asset pipeline. Rendering the templates is a breeze and doesn’t require a lot of configuration, but still it is not without limitations. Jade should serve common needs in rendering javascript templates, it’s ease of use and smooth integration certainly outweigh it’s limitations.

Frequently Asked Questions on Integrating Jade Templates into Rails for Cleaner Templates

What are the benefits of integrating Jade templates into Rails?

Jade templates offer a cleaner, more efficient way to write HTML. They are easy to read and write, and they reduce the amount of code you need to write. This can make your code more maintainable and easier to understand. Additionally, Jade templates support dynamic code, which means you can include variables and logic in your templates. This can make your templates more flexible and powerful.

How do I install Jade in my Rails project?

To install Jade in your Rails project, you need to add the ‘jade’ gem to your Gemfile. Then, run the ‘bundle install’ command to install the gem. After that, you can start using Jade in your project. Remember to restart your server after installing new gems.

How do I convert my existing ERB templates to Jade?

Converting ERB templates to Jade can be a bit tricky, as the syntax is quite different. However, there are tools available that can help with this process, such as html2jade. This tool can convert your HTML or ERB templates into Jade syntax, which can save you a lot of time.

Can I use Jade with Rails’ asset pipeline?

Yes, you can use Jade with Rails’ asset pipeline. You just need to make sure that your Jade files are in the right location and that they have the correct file extension (.jade). The asset pipeline will then compile your Jade templates into HTML when you deploy your application.

How do I use variables in Jade templates?

You can use variables in Jade templates by using the ‘=’ character. For example, if you have a variable called ‘title’, you can display it in your template like this: ‘h1= title’. This will output an h1 tag with the content of the ‘title’ variable.

Can I use loops and conditionals in Jade templates?

Yes, Jade supports both loops and conditionals. You can use the ‘each’ keyword to loop over an array or object, and you can use the ‘if’, ‘else if’, and ‘else’ keywords to create conditionals.

How do I include partials in Jade templates?

You can include partials in Jade templates by using the ‘include’ keyword. For example, if you have a partial called ‘_header.jade’, you can include it in your template like this: ‘include _header’.

Can I use Jade with Rails’ form helpers?

Yes, you can use Jade with Rails’ form helpers. However, the syntax is a bit different compared to ERB. You need to use the ‘-‘ character to write Ruby code in your Jade templates.

How do I debug Jade templates?

Debugging Jade templates can be a bit tricky, as the error messages can be cryptic. However, you can use the ‘inspect’ function to output the current state of your variables, which can help you track down errors.

Can I use Jade with other programming languages or frameworks?

Yes, Jade is not limited to Ruby on Rails. You can use it with any programming language or framework that supports it, such as Node.js, Express.js, and Meteor.

Hendra UziaHendra Uzia
View Author

Hendra is the software engineer of vidio.com, the largest video sharing website in Indonesia. He also contributes to the open source community on rspec-authorization and minitest-around.

GlennGRuby on Rails
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week