Erubis Users' Guide

5   Ruby on Rails Support

NOTICE: Rails 3 adopts Erubis as default default engine. You don't need to do anything at all when using Rails 3. This section is for Rails 2.

Erubis supports Ruby on Rails. This section describes how to use Erubis with Ruby on Rails.

5-1   Settings

Add the following code to your 'config/environment.rb' and restart web server. This replaces ERB in Rails by Erubis entirely.

config/environment.rb
require 'erubis/helpers/rails_helper'
#Erubis::Helpers::RailsHelper.engine_class = Erubis::Eruby # or Erubis::FastEruby
#Erubis::Helpers::RailsHelper.init_properties = {}
#Erubis::Helpers::RailsHelper.show_src = nil
#Erubis::Helpers::RailsHelper.preprocessing = false

Options:

Erubis::Helpers::RailsHelper.engine_class (=Erubis::Eruby)

Erubis engine class (default Erubis::Eruby).

Erubis::Helpers::RailsHelper.init_properties (={})

Optional arguments for Erubis::Eruby#initialize() method (default {}).

Erubis::Helpers::RailsHelper.show_src (=nil)

Whether to print converted Ruby code into log file. If true, Erubis prints coverted code into log file. If false, Erubis doesn't. If nil, Erubis prints when ENV['RAILS_ENV'] == 'development'. Default is nil.

Erubis::Helpers::RailsHelper.preprocessing (=false)

Enable preprocessing if true (default false).

5-2   Preprosessing

Erubis supports preprocessing of template files. Preprocessing make your Ruby on Rails application about 20-40 percent faster. To enable preprocessing, set Erubis::Helpers::RailsHelper.preprocessing to true in your 'environment.rb' file.

For example, assume the following template. This is slow because link_to() method is called every time when template is rendered.

<%= link_to 'Create', :action=>'create' %>

The following is faster than the above, but not flexible because url is fixed.

<a href="/users/create">Create</a>

Preprocessing solves this problem. If you use '[%= %]' instead of '<%= %>', preprocessor evaluate it only once when template is loaded.

[%= link_to 'Create', :action=>'create'%]

The above is evaluated by preprocessor and replaced to the following code automatically.

<a href="/users/create">Create</a>

Notice that this is done only once when template file is loaded. It means that link_to() method is not called when template is rendered.

If link_to() method have variable arguments, use _?() helper method.

<% for user in @users %>
[%= link_to _?('user.name'), :action=>'show', :id=>_?('user.id') %]
<% end %>

The above is evaluated by preprocessor when template is loaded and expanded into the following code. This will be much faster because link_to() method is not called when rendering.

<% for user in @users %>
<a href="/users/show/<%=user.id%>"><%=user.name%></a>
<% end %>

Preprocessing statement ([% %]) is also available as well as preprocessing expression ([%= %]).

<select name="state">
  <option value="">-</option>
[% for code in states.keys.sort %]
  <option value="[%= code %]">[%= states[code] %]</option>
[% end %]
</select>

The above will be evaluated by preprocessor and expanded into the following when template is loaded. In the result, rendering speed will be much faster because for-loop is not executed when rendering.

<select name="state">
  <option value="">-</option>
  <option value="AK">Alaska</option>
  <option value="AL">Alabama</option>
  <option value="AR">Arkansas</option>
  <option value="AS">American Samoa</option>
  <option value="AZ">Arizona</option>
  <option value="CA">California</option>
  <option value="CO">Colorado</option>
   ....
</select>

Notice that it is not recommended to use preprocessing with tag helpers, because tag helpers generate different html code when form parameter has errors or not.

Helper methods of Ruby on Rails are divided into two groups.

  • link_to() or _() (method of gettext package) are not need to call for every time as template is rendered because it returns same value when same arguments are passed. These methods can be got faster by preprocessing.
  • Tag helper methods should be called for every time as template is rendered because it may return differrent value even if the same arguments are passed. Preprocessing is not available with these methods.

In Ruby on Rails 2.0, _?('user_id') is OK but _?('user.id') is NG because the latter contains period ('.') character.

<!-- NG in Rails 2.0, because _?('') contains period -->
[%= link_to 'Edit', edit_user_path(_?('@user.id')) %]
[%= link_to 'Show', @user %]
[%= link_to 'Delete', @user, :confirm=>'OK?', :method=>:delete %]

<!-- OK in Rails 2.0 -->
<%= user_id = @user.id %>
[%= link_to 'Edit', edit_user_path(_?('user_id')) %]
[%= link_to 'Show', :action=>'show', :id=>_?('user_id') %]
[%= link_to 'Delete', {:action=>'destroy', :id=>_?('user_id')},
                      {:confirm=>'OK?', :method=>:delete} %]

5-3   Form Helpers for Preprocessing

(Experimental)

Erubis provides form helper methods for preprocessing. These are defined in 'erubis/helpers/rails_form_helper.rb'. If you want to use it, require it and include Erubis::Helpers::RailsFormHelper in 'app/helpers/applition_helper.rb'

app/helpers/xxx_helper.rb
require 'erubis/helpers/rails_form_helper'
module ApplicationHelper
  include Erubis::Helpers::RailsFormHelper
end

Form helper methods defined in Erubis::Helpers::RailsFormHelper are named as 'pp_xxxx' ('pp' represents preprocessing).

Assume the following view template:

_form.rhtml
 <p>
  Name: <%= text_field :user, :name %>
 </p>
 <p>
  Name: [%= pp_text_field :user, :name %]
 </p>

Erubis preprocessor converts it to the following eRuby string:

preprocessed
 <p>
  Name: <%= text_field :user, :name %>
 </p>
 <p>
  Name: <input id="stock_name" name="stock[name]" size="30" type="text" value="<%=h @stock.name%>" />
 </p>

Erubis converts it to the following Ruby code:

Ruby code
 _buf << ' <p>
  Name: '; _buf << ( text_field :stock, :name ).to_s; _buf << '
'; _buf << ' </p>
 <p>
  Name: <input id="stock_name" name="stock[name]" size="30" type="text" value="'; _buf << (h @stock.name).to_s; _buf << '" />
 </p>
';

The above Ruby code shows that text_field() is called everytime when rendering, but pp_text_field() is called only once when template is loaded. This means that pp_text_field() with preprocessing makes view layer very fast.

Module Erubis::Helpers::RailsFormHelper defines the following form helper methods.

  • pp_render_partial(basename)
  • pp_form_tag(url_for_options={}, options={}, *parameters_for_url, &block)
  • pp_text_field(object_name, method, options={})
  • pp_password_field(object_name, method, options={})
  • pp_hidden_field(object_name, method, options={})
  • pp_file_field(object_name, method, options={})
  • pp_text_area(object_name, method, options={})
  • pp_check_box(object_name, method, options={}, checked_value="1", unchecked_value="0")
  • pp_radio_button(object_name, method, tag_value, options={})
  • pp_select(object, method, collection, options={}, html_options={})
  • pp_collection_select(object, method, collection, value_method, text_method, options={}, html_options={})
  • pp_country_select(object, method, priority_countries=nil, options={}, html_options={})
  • pp_time_zone_select(object, method, priority_zones=nil, options={}, html_options={})
  • pp_submit_tag(value="Save changes", options={})
  • pp_image_submit_tag(source, options={})

Notice that pp_form_for() is not provided.

CAUTION: These are experimental and may not work in Ruby on Rails 2.0.

5-4   Others

  • ActionView::Helpers::CaptureHelper#capture() and ActionView::Helpers::Texthelper#concat() are available.
  • Form helper methods are not tested in Ruby on Rails 2.0.
  • ERB::Util.h() is redefined if you require 'erubis/helpers/rails_helper.rb'. Original definition of ERB::Util.h() is the following and it is slow because it scans string four times.
     def html_escape(s)
       s.to_s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
     end
     alias h html_escape
    

    New definition in 'erubis/helpers/rails_helper.rb' is faster than the above because it scans string only once.

     ESCAPE_TABLE = { '&'=>'&amp;', '<'=>'&lt;', '>'=>'&gt;', '"'=>'&quot;', "'"=>'&#039;', }
     def h(value)
       value.to_s.gsub(/[&<>"]/) { |s| ESCAPE_TABLE[s] }
     end
    

    Notice that the new definition may be slow if string contains many '< > & "' characters because block is call many time. You should use ERB::Util.html_hscape() if string contains a lot of '< > & "' characters.