Isnor Creative
Isnor Creative Blog
Ruby, Ruby on Rails, Ember, Elm, Phoenix, Elixir, React, Vue

Jan 27, 2015

Ruby on Rails – using Handlebars To Generate Bootstrap Modals

I’ve been learning Ember.js over the course of the past year and it’s given me ideas that I’ve been pleased to be able to use in Ruby on Rails projects as well; one such idea is using Handlebars.

I’ve been aware of JS templating languages for years but either did not see a need to use them, or perhaps didn’t quite realize the possibilities. I’ve recently had a few projects where a large number of partials were being rendered to a page, and each needed it’s own Bootstrap modal – which involves a fair bit of DOM – including a large image –– this led to pretty poor performance.

I came to the realization that it would make more sense to load in the modal content only on demand with an XHR request.

Normally in a scenario like this I might have been inclinded to either build a string of HTML at runtime in javascript, or to use a js.erb view to render a partial and insert it using jQuery. In this case though you’d be either building a fairly intense HTMl string in jQuery, or re-rendering the same partial for the modal countless times.

That line of thinking led to wonder if perhaps Handlebars could improve this scenario. I was pleased to see that I can now send back only a bit of JSON from the server and use that JSON to render a Handlebars template.

I started by looking into using Mustache, but realized that I needed to iterate through associated records, and so Handlebars made more sense.

It worked nicely and dramatically sped up the page performance.

Gemfile – I’m using Active Model Serializers to produce the JSON response, and Bower-Rails to install Handlebars:

gem 'active_model_serializers', '0.8.3'    
gem 'bower-rails'

Install the gems:

$ bundle 
$ spring rails g bower_rails:initialize

Add Handlebars to Bowerfile:

asset 'handlebars'

Install Handlebars:

$ bundle exec rake bower:install

Add Handlebars to application.js:

//= require handlebars/handlebars    

items.js - this is where Handlebars comes in:

$(document).ready(function () {
  var source = $("#modal-template").html();
  itemModaltemplate = Handlebars.compile(source);
});
$(document).on('click', '[data-trigger="modal"]', function () {
  var item_id = $(this).data('target');
  $.getJSON('/items/' + item_id + '.json').done(function (data) {
    var html  = itemModaltemplate(data.item);
    $('#item_modal').remove();    
    $('body').append(html);
    $('#item_modal').modal({show: true, background: true});
  });
});

application.html.haml - render the modal template:

= render "items/modal"

items/_item.html.haml:

%a.btn.btn-info{data: {trigger: 'modal', target: item.id}} Info

items/_modal.html.erb:

<script type="text/x-handlebars" id="modal-template">
  <div class="item-modal modal fade in" id="item_modal" role="dialog" aria-hidden="false">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header"><h4 class="modal-title">Title</h4></div>
        <div class="modal-body">Body</div>
        <div class="modal-footer">Footer</div>
      </div>
    </div>
  </div>
</script>

serializers/item_serializer.rb:

class ItemSerializer < ActiveModel::Serializer
  has_many :other_things

  attributes :id, :title, :bg_image

  def bg_image
    object.cover.url(:original)
  end

end

controllers/items_controller.rb:

def show
  @item = Item.find(params[:id])

  respond_to do |format|
    format.html
    format.json { render json: @item, serializer: ItemSerializer }
  end
end

css:

.item-modal {
  display: none;
}

Edit: I’ve found that this process can be cleaned up and made a bit more elegant with the help of the handlebars_assets gem which moves the handlebars templates out of Rails views, and into assets/javascripts/templates where they graduate to proper .hbs template files, which are automatically precompiled as a part of the asset pipeline. This reduces the process of manually compiling each template as I’ve done above within $(document).ready(). Both ways work just fine, but especially where a number of different Handlebars templates are going to be used, the gem may be the better bet.


I am available for Ruby on Rails and Ember consulting work – get in touch to learn more.

Gordon B. Isnor

Gordon B. Isnor writes about Ruby on Rails, Ember.js, Elm, Elixir, Phoenix, React, Vue and the web.
If you enjoyed this article, you may be interested in the occasional newsletter.

I am now available for project work. I have availability to build greenfield sites and applications, to maintain and update/upgrade existing applications, team augmentation. I offer website/web application assessment packages that can help with SEO/security/performance/accessibility and best practices. Let’s talk

comments powered by Disqus