This component provides a great deal of view helpers related to html markup generation. There are helpers for generating tags, forms, links, images, and more. Most of the basic methods should be very familiar to anyone who has used rails view helpers.
Output helpers are a collection of important methods for managing, capturing and displaying output in various ways and is used frequently to support higher-level helper functions. There are three output helpers worth mentioning: content_for
, capture_html
, and concat_content
The content_for functionality supports capturing content and then rendering this into a different place such as within a layout. One such popular example is including assets onto the layout from a template:
# app/views/site/index.erb
...
<% content_for :assets do %>
<%= stylesheet_link_tag 'index', 'custom' %>
<% end %>
...
Added to a template, this will capture the includes from the block and allow them to be yielded into the layout:
# app/views/layout.erb
...
<head>
<title>Example</title>
<%= stylesheet_link_tag 'style' %>
<%= yield_content :assets %>
</head>
This will automatically insert the contents of the block (in this case a stylesheet include) into the location the content is yielded within the layout.
You can also check if a content_for
block exists for a given key using content_for?
:
# app/views/layout.erb
<% if content_for?(:assets) %>
<div><%= yield_content :assets %></div<
<% end %>
The capture_html
and the concat_content
methods allow content to be manipulated and stored for use in building additional helpers accepting blocks or displaying information in a template. One example is the use of these in constructing a simplified ‘form_tag’ helper which accepts a block.
# form_tag '/register' do ... end
def form_tag(url, options={}, &block)
# ... truncated ...
inner_form_html = capture_html(&block)
concat_content '<form>' + inner_form_html + '</form>'
end
This will capture the template body passed into the form_tag block and then append the content to the template through the use of concat_content
. Note have been built to work for both haml and erb templates using the same syntax.
The list of defined helpers in the ‘output helpers’ category:
content_for(key, &block)
content_for?(key)
method.content_for(:head) { …content… }
content_for(:head) { |param1, param2| …content… }
yield_content(key, *args)
yield_content :head
yield_content :head, param1, param2
capture_html(*args, &block)
capture_html(&block)
=> “…html…”concat_content(text="")
concat_content(“This will be output to the template buffer in erb or haml”)
Tag helpers are the basic building blocks used to construct html ‘tags’ within a view template. There are three major functions for this category: tag
, content_tag
and input_tag
.
The tag and content_tag are for building arbitrary html tags with a name and specified options. If the tag contains ‘content’ within then content_tag
is used. For example:
The input_tag is used to build tags that are related to accepting input from the user:
input_tag :text, :class => "demo" # => <input type='text' class='demo' />
input_tag :password, :value => "secret", :class => "demo"
Note that all of these accept html options and result in returning a string containing html tags.
The list of defined helpers in the ‘tag helpers’ category:
tag(name, options=nil, open=false)
tag(:br, :style => ‘clear:both’, :open => true)
=> <br style="clear:both">
content_tag(name, content, options=nil, &block)
content_tag(:p, “demo”, :class => ‘light’)
=> <p class="light">demo</p>
content_tag(:p, :class => ‘dark’) { …content… }
=> <p class="dark">...content...</p>
input_tag(type, options = {})
input_tag :text, :class => “demo”
input_tag :password, :value => “secret”, :class => “demo”
Asset helpers are intended to help insert useful html onto a view template such as ‘flash’ notices, hyperlinks, mail_to links, images, stylesheets and javascript. An example of their uses would be on a simple view template:
# app/views/example.haml
...
%head
= stylesheet_link_tag 'layout'
= javascript_include_tag 'application'
= favicon_tag 'images/favicon.png'
%body
...
= flash_tag :notice
%p= link_to 'Blog', '/blog', :class => 'example'
%p Mail me at #{mail_to '[email protected]', "Fake Email Link", :cc => "[email protected]"}
%p= image_tag 'padrino.png', :width => '35', :class => 'logo'
The list of defined helpers in the ‘asset helpers’ category:
flash_tag(kind, options={})
flash_tag(:notice, :class => ‘flash’, :id => ‘flash-notice’)
link_to(*args, &block)
link_to ‘click me’, ‘/dashboard’, :class => ‘linky’
link_to ‘click me’, ‘/dashboard’, :class => ‘linky’, :if => @foo.present?
link_to ‘click me’, ‘/dashboard’, :class => ‘linky’, :unless => @foo.blank?
link_to ‘click me’, ‘/dashboard’, :class => ‘linky’, :unless => :current
link_to(‘/dashboard’, :class => ‘blocky’) { …content… }
mail_to(email, caption=nil, mail_options={})
mail_to “[email protected]”
mail_to “[email protected]”, “My Email”, :subject => “Feedback”, :cc => ‘[email protected]’
image_tag(url, options={})
image_tag(‘icons/avatar.png’)
stylesheet_link_tag(*sources)
stylesheet_link_tag ‘style’, ‘application’, ‘layout’
javascript_include_tag(*sources)
javascript_include_tag ‘application’, ‘special’
favicon_tag(source, options={})
favicon_tag ‘images/favicon.ico’, :type => ‘image/ico’
feed_tag(mime,source, options={})
feed_tag :atom, url(:blog, :posts, :format => :atom), :title => “ATOM”
By default, all ‘assets’ including images, scripts, and stylesheets have a timestamp appended at the end to clear the stale cache for the item when modified. To disable this, simply put the setting disable :asset_stamp
in your application configuration within app/app.rb
.
Form helpers are the ‘standard’ form tag helpers you would come to expect when building forms. A simple example of constructing a non-object form would be:
# app/views/example.haml
= form_tag '/destroy', :class => 'destroy-form', :method => 'delete' do
= flash_tag(:notice)
= field_set_tag do
%p
= label_tag :username, :class => 'first'
= text_field_tag :username, :value => params[:username]
%p
= label_tag :password, :class => 'first'
= password_field_tag :password, :value => params[:password]
%p
= label_tag :strategy
= select_tag :strategy, :options => ['delete', 'destroy'], :selected => 'delete'
%p
= check_box_tag :confirm_delete
= field_set_tag(:class => 'buttons') do
= submit_tag "Remove"
The list of defined helpers in the ‘form helpers’ category:
form_tag(url, options={}, &block)
form_tag(‘/register’, :class => ‘example’) { … }
field_set_tag(*args, &block)
field_set_tag(:class => ‘office-set’) { }
field_set_tag(“Office”, :class => ‘office-set’) { }
error_messages_for(:record, options={})
error_messages_for :user
label_tag(name, options={}, &block)
label_tag :username, :class => ‘long-label’
label_tag(:username, :class => ‘blocked-label’) { … }
hidden_field_tag(name, options={})
hidden_field_tag :session_key, :value => ‘secret’
text_field_tag(name, options={})
text_field_tag :username, :class => ‘long’
text_area_tag(name, options={})
text_area_tag :username, :class => ‘long’
password_field_tag(name, options={})
password_field_tag :password, :class => ‘long’
number_field_tag(name, options={})
number_field_tag :age, :class => ‘long’
telephone_field_tag(name, options={})
telephone_field_tag :mobile, :class => ‘long’
email_field_tag(name, options={})
email_field_tag :email, :class => ‘long’
search_field_tag(name, options={})
search_field_tag :query, :class => ‘long’
url_field_tag(name, options={})
url_field_tag :image_source_url, :class => ‘long’
check_box_tag(name, options={})
check_box_tag :remember_me, :checked => true
radio_button_tag(name, options={})
radio_button_tag :gender, :value => ‘male’
select_tag(name, settings={})
select_tag(:favorite_color, :options => [‘1’, ‘2’, ‘3’], :selected => ‘1’)
select_tag(:more_color, :options => [[‘label’, ‘1’], [‘label2’, ‘2’]])
select_tag(:multiple_color, :options => [‘1’, ‘2’, ‘3’], :multiple => true,
:selected => [‘1’, ‘3’])
file_field_tag(name, options={})
file_field_tag :photo, :class => ‘long’
submit_tag(caption, options={})
submit_tag “Create”, :class => ‘success’
button_tag(caption, options={})
button_tag “Cancel”, :class => ‘clear’
image_submit_tag(source, options={})
image_submit_tag “submit.png”, :class => ‘success’
Form builders are full-featured objects allowing the construction of complex object-based forms using a simple, intuitive syntax.
A form_for using these basic fields might look like:
# app/views/example.haml
= form_for @user, '/register', :id => 'register' do |f|
= f.error_messages
%p
= f.label :username, :caption => "Nickname"
= f.text_field :username
%p
= f.label :email
= f.text_field :email
%p
= f.label :password
= f.password_field :password
%p
= f.label :is_admin, :caption => "Admin User?"
= f.check_box :is_admin
%p
= f.label :color, :caption => "Favorite Color?"
= f.select :color, :options => ['red', 'black']
%p
= fields_for @user.location do |location|
= location.text_field :street
= location.text_field :city
%p
= f.submit "Create", :class => 'button'
The list of defined helpers in the ‘form builders’ category:
form_for(object, url, settings={}, &block)
form_for(@user, ‘/register’, :id => ‘register’) { |f| …field-elements… }
form_for(:user, ‘/register’, :id => ‘register’) { |f| …field-elements… }
fields_for(object, settings={}, &block)
fields_for @user.assignment do |assignment| … end
fields_for :assignment do |assigment| … end
The following are fields provided by AbstractFormBuilder that can be used within a form_for or fields_for:
error_messages(options={})
f.errors_messages
label(field, options={})
f.label :name, :class => ‘long’
text_field(field, options={})
f.text_field :username, :class => ‘long’
check_box(field, options={})
f.check_box :remember_me, :uncheck_value => ‘false’
radio_button(field, options={})
f.radio_button :gender, :value => ‘male’
hidden_field(field, options={})
f.hidden_field :session_id, :class => ‘hidden’
text_area(field, options={})
f.text_area :summary, :class => ‘long’
password_field(field, options={})
f.password_field :secret, :class => ‘long’
number_field(field, options={})
f.number_field :age, :class => ‘long’
telephone_field(field, options={})
f.telephone_field :mobile, :class => ‘long’
email_field(field, options={})
f.email_field :email, :class => ‘long’
search_field(field, options={})
f.search_field :query, :class => ‘long’
url_field(field, options={})
f.url_field :image_source, :class => ‘long’
file_field(field, options={})
f.file_field :photo, :class => ‘long’
select(field, options={})
f.select(:state, :options => [‘California’, ‘Texas’, ‘Wyoming’])
f.select(:state, :collection => @states, :fields => [:name, :id])
f.select(:state, :options => […], :include_blank => true)
submit(caption, options={})
f.submit “Update”, :class => ‘long’
image_submit(source, options={})
f.image_submit “submit.png”, :class => ‘long’
There is also an additional StandardFormBuilder which builds on the abstract fields that can be used within a form_for.
A form_for using these standard fields might be:
# app/views/example.haml
= form_for @user, '/register', :id => 'register' do |f|
= f.error_messages
= f.text_field_block :name, :caption => "Full name"
= f.text_field_block :email
= f.check_box_block :remember_me
= f.select_block :fav_color, :options => ['red', 'blue']
= f.password_field_block :password
= f.submit_block "Create", :class => 'button'
and would generate this html (with each input contained in a paragraph and containing a label):
<form id="register" action="/register" method="post">
<label for="user_name">Full name:</label>
<input type="text" id="user_name" name="user[name]" />
...omitted...
<input type="submit" value="Create" class="button" />
</form>
The following are fields provided by StandardFormBuilder that can be used within a form_for or fields_for:
text_field_block(field, options={}, label_options={})
text_field_block(:nickname, :class => ‘big’, :caption => “Username”)
text_area_block(field, options={}, label_options={})
text_area_block(:about, :class => ‘big’)
password_field_block(field, options={}, label_options={})
password_field_block(:code, :class => ‘big’)
file_field_block(field, options={}, label_options={})
file_field_block(:photo, :class => ‘big’)
check_box_block(field, options={}, label_options={})
check_box_block(:remember_me, :class => ‘big’)
select_block(field, options={}, label_options={})
select_block(:country, :option => [‘USA’, ‘Canada’])
submit_block(caption, options={})
submit_block(:username, :class => ‘big’)
image_submit_block(source, options={})
image_submit_block(‘submit.png’, :class => ‘big’)
You can also easily build your own FormBuilder which allows for customized fields and behavior:
class MyCustomFormBuilder < AbstractFormBuilder
# Here we have access to a number of useful variables
#
# ** template (use this to invoke any helpers)(ex. template.hidden_field_tag(...))
# ** object (the record for this form) (ex. object.valid?)
# ** object_name (object's underscored type) (ex. object_name => 'admin_user')
#
# We also have access to self.field_types => [:text_field, :text_area, ...]
# In addition, we have access to all the existing field tag
# helpers (text_field, hidden_field, file_field, ...)
end
Once a custom builder is defined, any call to form_for can use the new builder:
= form_for @user, '/register', :builder => 'MyCustomFormBuilder', :id => 'register' do |f|
...fields here...
The form builder can even be made into the default builder when form_for is invoked:
# anywhere in the Padrino or Sinatra application
set :default_builder, 'MyCustomFormBuilder'
And there you have it, a fairly complete form builder solution for Padrino (and Sinatra). I hope to create or merge in an even better ‘default’ form_builder in the near future.
Available in the 0.9.21 Padrino release is support for nested object form helpers. This allows forms to have arbitrarily complex nested forms that can build multiple related objects together. Let’s take a simple example of a person with an address. Here are the related psuedo models:
class Person < ORM::Base
has_many :addresses, :class_name => 'Address'
accepts_nested_attributes_for :addresses, :allow_destroy => true
end
class Address < ORM::Base
belongs_to :person
end
The model declarations are dependent on your chosen ORM. Check the documentation to understand how to declare nested attributes in your given ORM component. Given those models and enabling nested attributes for the association, the following view will allow nested form creation:
# app/views/person/_form.html.haml
= form_for @person, '/person/create' do |f|
= f.text_field :name
= f.text_field :favorite_color
= f.fields_for :addresses do |address_form|
= address_form.label :street
= address_form.text_field :street
= address_form.label :city
= address_form.text_field :city
- unless address_form.object.new_record?
= address_form.check_box '_destroy'
= address_form.label '_destroy', :caption => 'Remove'
= submit_tag "Save"
This will present a form that allows the person’s name and color to be set along with their first address. Using this functionality, the controller does not need to change whatsoever as the nested data will be passed in and instantiated as part of the parent model.
Format helpers are several useful utilities for manipulating the format of text to achieve a goal.
The four format helpers are escape_html
, distance_of_time_in_words
, time_ago_in_words
, and js_escape_html
.
The escape_html and js_escape_html function are for taking an html string and escaping certain characters.
escape_html
will escape ampersands, brackets and quotes to their HTML/XML entities. This is useful to sanitize user content before displaying this on a template. js_escape_html
is used for passing javascript information from a js template to a javascript function.
escape_html('<hello>&<goodbye>') # => <hello>&<goodbye>
There is also an alias for escape_html called h
for even easier usage within templates.
Format helpers also includes a number of useful text manipulation functions such as simple_format
, pluralize
, word_wrap
, and truncate
.
simple_format("hello\nworld") # => "<p>hello<br/>world</p>"
pluralize(2, 'person') => '2 people'
word_wrap('Once upon a time', :line_width => 8) => "Once upon\na time"
truncate("Once upon a time in a world far far away", :length => 8) => "Once upon..."
truncate_words("Once upon a time in a world far far away", :length => 4) => "Once upon a time..."
highlight('Lorem dolor sit', 'dolor') => "Lorem <strong class="highlight">dolor</strong> sit"
These helpers can be invoked from any route or view within your application.
The list of defined helpers in the ‘format helpers’ category:
simple_format(text, html_options)
simple_format(“hello\nworld”)
=> "<p>hello<br/>world</p>"
pluralize(count, singular, plural = nil)
pluralize(2, ‘person’)
=> ‘2 people’word_wrap(text, *args)
word_wrap(‘Once upon a time’, :line_width => 8)
=> “Once upon\na time”truncate(text, *args)
truncate(“Once upon a time in a world far far away”, :length => 8)
=> “Once upon…”truncate_words(text, *args)
highlight(text, words, *args)
highlight(‘Lorem ipsum dolor sit amet’, ‘dolor’)
escape_html
(alias h
and h!
)
strip_tags(html)
distance_of_time_in_words(from_time, to_time = 0)
distance_of_time_in_words(2.days.ago)
=> “2 days”distance_of_time_in_words(5.minutes.ago)
=> “5 minutes”distance_of_time_in_words(2800.days.ago)
=> “over 7 years”time_ago_in_words(from_time)
time_ago_in_words(2.days.ago)
=> “2 days”time_ago_in_words(1.day.from_now)
=> “tomorrow”js_escape_html(html_content)
js_escape_html("<h1>Hey</h1>")
This component provides a number of rendering helpers making the process of displaying templates a bit easier. This plugin also has support for useful additions such as partials (with support for :collection) for the templating system.
Using render plugin helpers is extremely simple. If you want to render an erb template in your view path:
render :erb, 'path/to/erb/template'
or using haml templates works just as well:
render :haml, 'path/to/haml/template'
There is also a method which renders the first view matching the path and removes the need to define an engine:
render 'path/to/any/template'
It is worth noting these are mostly for convenience. With nested view file paths in Sinatra, this becomes tiresome:
haml :"the/path/to/file"
erb "/path/to/file".to_sym
Finally, we have the all-important partials support for rendering mini-templates onto a page:
partial 'photo/item', :object => @photo, :locals => { :foo => 'bar' }
partial 'photo/item', :collection => @photos
This works as you would expect and also supports the collection counter inside the partial item_counter
# /views/photo/_item.haml
# Access to collection counter with <partial_name>_counter i.e item_counter
# Access the object with the partial_name i.e item
The list of defined helpers in the ‘render helpers’ category:
render(engine, data, options, locals)
render ‘user/new’
render :erb, ‘users/new’, :layout => false
partial(template, *args)
partial ‘photo/item’, :object => @photo, :locals => { :foo => ‘bar’ }
partial ‘photo/item’, :collection => @photos
In addition to the helpers provided by Padrino out of the box, you can also add your own helper methods and classes that will be accessible within any controller or view automatically.
To define a helper method, simply use an existing helper file (created when generating a controller) or define your own file in app/helpers
within your application. Methods can be made available within you controller by simply wrapping the methods in the helpers
block:
# app/helpers/some_helper.rb
MyAppName.helpers do
def some_method
# ...do something here...
end
end
You can also define entire classes for use as helpers just as easily:
# app/helpers/some_helper.rb
class SomeHelper
def self.do_something
# ...do something here...
end
end
These helpers can then easily be invoked in any controllers or templates within your application:
# app/controllers/posts.rb
MyAppName.controllers :posts do
get :index do
some_method # helper method
SomeHelper.do_something # helper class
end
end
Use these in situations where you wish to cleanup your controller or your view code. Helpers are particularly useful for DRY’ing up repeated use of the same markup or behavior. Note that helper methods and objects should be reloaded automatically for you in development.
In addition to the helpers above, certain helpers also have certain unobtrusive javascript options that are available to be used with any of the javascript adapters packaged with padrino. Once your app has been generated with a particular javascript adapter, you can utilize the baked in support with the link_to
and form_for
tags.
To generate a ‘remote’ form in a view:
# /app/views/users/new.html.haml
= form_for :user, url(:create, :format => :js), :remote => true do |f|
.content=partial "/users/form"
which will generate the following unobtrusive markup:
<form data-remote="true" action="/items/create.js" method="post">
<div class="content">
<input type="text" id="post_title" name="post[title]">
<input type="submit" value="Create">
</div>
</form>
# /app/controllers/users.rb
post :create, :provides => :js do
@user = User.new(params[:user])
if @user.save
"$('form.content').html('#{partial("/users/form")}');"
else
"alert('User is not valid');"
end
end
A remote form, when submitted by the user, invokes an xhr request to the specified url (with the appropriate form parameters) and then evaluates the response as javascript.
To generate a ‘remote’ link in a view:
link_to "add item", url(:items, :new, :format => :js), :remote => true
which will generate the following unobtrusive markup:
<a href="/items/new.js" data-remote="true">add item</a>
A remote link, when clicked by the user, invokes an xhr request to the specified url and then evaluates the response as javascript.
To generate a ‘confirmation’ link in a view:
link_to "delete item", url(:items, :destroy, :format => :js), :confirm => "Are You Sure?"
which will generate the following unobtrusive markup:
<a data-confirm="Are You Sure?" href="/posts/destroy/7">[destroy]</a>
A link with confirmation, when clicked by the user, displays an alert box confirming the action before invoking the link.
To generate a ‘method’ link in a view:
link_to "logout", url(:session, :destroy, :format => :js), :method => :delete
which will generate the following unobtrusive markup:
<a data-method="delete" href="/posts/destroy/7" rel="nofollow">[destroy]</a>
A link with a custom method, when clicked by the user, visits the link using the http method specified rather than via the ‘GET’ method.
Note: In order for the unobstrusive javascript to work, you must be sure to include the chosen javascript framework and ujs adapter in your views (or layout). For instance, if I selected jquery for my project:
# /apps/views/layouts/application.haml
= javascript_include_tag 'jquery', 'jquery-ujs', 'application'
This will ensure jquery and the jquery ujs adapter are properly loaded to work with the helpers listed above.