Chapter 11. All about Helpers

Thank you for helping Helpers Helping the Helpless. Your help was very...helpful!

—Mrs. Duong in the movie The Weekenders

Throughout the book so far, we’ve already covered some of the helper methods provided by Rails to help you assemble the user interface of your web application. This chapter lists and explains all the helper modules and their methods, followed by instructions on effectively creating your own helpers.


Note

This chapter is essentially reference material. Although every effort has been made to make it readable straight through, you will notice that coverage of Action View’s helper modules is arranged alphabetically, starting with ActiveModelHelper and ending with UrlHelper. Within each module’s section, the methods are broken up into logical groups whenever appropriate.


This chapter is published under the Creative Commons Attribution-ShareAlike 4.0 license, http://creativecommons.org/licenses/by-sa/4.0/.

11.1 ActiveModelHelper

The ActiveModelHelper module contains helper methods for quickly creating forms from objects that follow Active Model conventions, starting with Active Record models. The form method is able to create an entire form for all the basic content types of a given record. However, it does not know how to assemble user-interface components for manipulating associations. Most Rails developers assemble their own forms from scratch using methods from FormHelper instead of using this module. However, this module does contain some useful helpers for reporting validation errors in your forms that you will use regularly.

Note that since Rails 3, you must add the following gem to your Gemfile in order to use this module.

gem 'dynamic_form'

11.1.1 Reporting Validation Errors

The error_message_on and error_messages_for methods help you add formatted validation error information to your templates in a consistent fashion.

11.1.1.1 error_message_on(object, method, *options)

Returns a div tag containing the error message attached to the specified method on the object, if one exists. It’s useful for showing validation errors inline next to the corresponding form field. The object argument of the method can be an actual object reference or a symbol corresponding to the name of an instance variable. The method should be a symbol corresponding to the name of the attribute on the object for which to render an error message.

The contents can be specialized with options for pre- and post-text and custom CSS class.

prepend_text: string Fragment to prepend to error messages generated.

append_text: string Fragment to append to error messages generated.

css_class: class_name CSS class name for div generated wrapping the error message. Defaults to formError.

Use of this method is common when the user-interface requirements specify individual validation messages per input field of a form, as in the following real-life example:

1 .form_field
2   .field_label
3     %span.required *
4     %label First Name
5   .textual
6     = form.text_field :first_name
7     = form.error_message_on :first_name

As in the example, the error_message_on helper is most commonly accessed via the form block variable of form_for and its variants. When used via the form variable, you leave off the first argument (specifying the object) since it’s implied.

11.1.1.2 error_messages_for(*params)

Returns a div tag containing all the error messages for all the objects held in instance variables identified as parameters.

1 = form_for @person do |form|
2   = form.error_messages
3   .text-field
4     = form.label :name, "Name"
5     = form.text_field :name

As in the example, the error_message_for helper is most commonly accessed via the form block variable of form_for and its variants. When used via the form variable, it is called error_messages and you leave off the first argument (specifying the object) since it’s implied.

This method was used by Rails scaffolding before version 3 but rarely in real production applications. The Rails API documentation advises you to use this method’s implementation as inspiration to meet your own requirements:

This is a prepackaged presentation of the errors with embedded strings and a certain HTML structure. If what you need is significantly different from the default presentation, it makes plenty of sense to access the object.errors instance yourself and set it up. View the source of this method to see how easy it is.

We’ll go ahead and reproduce the source of the method here with the warning that you should not try to use it as inspiration unless you have a good grasp of Ruby! On the other hand, if you have time to study the way that this method is implemented, it will definitely teach you a lot about the way that Rails is implemented, which is its own distinctive flavor of Ruby.

 1 def error_messages_for(*params)
 2   options = params.extract_options!.symbolize_keys
 3
 4   objects = Array.wrap(options.delete(:object) || params).map do |object|
 5     object = instance_variable_get("@#{object}") unless object.
 6       respond_to?(:to_model)
 7     object = convert_to_model(object)
 8
 9     if object.class.respond_to?(:model_name)
10      options[:object_name] ||= object.class.model_name.human.downcase
11     end
12
13     object
14   end
15
16   objects.compact!
17   count = objects.inject(0) { |sum, object| sum + object.errors.count }
18
19   unless count.zero?
20     html = {}
21     [:id, :class].each do |key|
22       if options.include?(key)
23         value = options[key]
24         html[key] = value unless value.blank?
25       else
26         html[key] = 'error_explanation'
27       end
28     end
29     options[:object_name] ||= params.first
30
31     I18n.with_options locale: options[:locale],
32       scope: [:activerecord, :errors, :template] do |locale|
33       header_message = if options.include?(:header_message)
34         options[:header_message]
35       else
36         locale.t :header, count: count,
37           model: options[:object_name].to_s.gsub('_', ' ')
38       end
39
40       message = options.include?(:message) ? options[:message] : locale.t(:body)
41
42       error_messages = objects.sum do |object|
43         object.errors.full_messages.map do |msg|
44           content_tag(:li, msg)
45         end
46       end.join.html_safe
47
48       contents = ''
49       contents << content_tag(options[:header_tag] ||
50          :h2, header_message) unless header_message.blank?
51       contents << content_tag(:p, message) unless message.blank?
52       contents << content_tag(:ul, error_messages)
53
54       content_tag(:div, contents.html_safe, html)
55     end
56   else
57     ''
58   end
59 end

Later on in the chapter we’ll talk extensively about writing your own helper methods.

11.1.2 Automatic Form Creation

The next couple of methods are used for automatic field creation. You can try using them too, but I suspect that their usefulness is somewhat limited in real applications.

11.1.2.1 form(name, options)

Returns an entire form with input tags and everything for a named model object. Here are the code examples given in the dynamic form API documentation, using a hypothetical Post object from a bulletin board application as an example:

 1 form("post")
 2 # => <form action='/posts/create' method='post'>
 3 #      <p>
 4 #        <label for="post_title">Title</label><br />
 5 #        <input id="post_title" name="post[title]" size="30"
         type="text"

 6 #          value="Hello World" />
 7 #      </p>
 8 #      <p>
 9 #        <label for="post_body">Body</label><br />
10 #        <textarea cols="40" id="post_body" name="post[body]"
11 #          rows="20"></textarea>
12 #      </p>
13 #      <input name="commit" type="submit" value="Create" />
14 #    </form>

Internally, the method calls record.persisted? to infer whether the action for the form should be create or update. It is possible to explicitly specify the action of the form (and the value of the submit button along with it) by using the :action option.

If you need the form to have its enctype set to multipart, useful for file uploads, set the options[:multipart] to true.

You can also pass in an :input_block option, using Ruby’s Proc.new idiom to create a new anonymous code block. The block you supply will be invoked for each content column of your model, and its return value will be inserted into the form.

 1 form("entry", action: "sign",
 2      input_block: Proc.new { |record, column|
 3        "#{column.human_name}: #{input(record, column.name)}<br />"
 4 })
 5 # => <form action="/entries/sign" method="post">
 6 #       Message:
 7 #       <input id="entry_message" name="entry[message]" size="30"
 8 #         type="text" /><br />
 9 #       <input name="commit" type="submit" value="Sign" />
10 #     </form>

That example’s builder block, as it is referred to in the dynamic_form API docs, uses the input helper method, which is also part of this module and is covered in the next section of this chapter.

Finally, it’s also possible to add additional content to the form by giving the call to form a block, as in the following snippet:

1 form("entry", action: "sign") do |form|
2   form << content_tag("b", "Department")
3   form << collection_select("department", "id", @departments, "id", "name")
4 end

The block is yielded a string accumulator (named form in the example), to which you append any additional content that you want to appear between the main input fields and the submit tag.

11.1.2.2 input(name, method, options)

The appropriately named input method takes some identifying information and automatically generates an HTML input tag based on an attribute of an Active Record model. Going back to the Post example used in the explanation of form, here is the code snippet given in the Rails API docs:

1 input("post", "title")
2 # => <input id="post_title" name="post[title]" size="30"
3 #       type="text" value="Hello World" />

To quickly show you the types of input fields generated by this method, I’ll simply reproduce a portion of the code from the module itself:

 1 def to_tag(options = {})
 2   case column_type
 3     when :string
 4       field_type = @method_name.include?("password") ?
 5       "password" : "text"
         to_input_field_tag(field_type, options)
 6     when :text
 7       to_text_area_tag(options)
 8     when :integer, :float, :decimal
 9       to_input_field_tag("text", options)
10     when :date
11       to_date_select_tag(options)
12     when :datetime, :timestamp
13       to_datetime_select_tag(options)
14     when :time
15       to_time_select_tag(options)
16     when :boolean
17       to_boolean_select_tag(options).html_safe
18   end
19 end

11.1.3 Customizing the Way Validation Errors Are Highlighted

By default, when Rails marks a field in your form that failed a validation check, it does so by wrapping that field in a div element with the class name field_with_errors. This behavior is customizable, since it is accomplished via a Proc object stored as a configuration property of the ActionView::Base class:

1 module ActionView
2   class Base
3     cattr_accessor :field_error_proc
4     @@field_error_proc = Proc.new{ |html_tag, instance|
5       "<div class="field_with_errors">#{html_tag}</div>".
         html_safe
6     }
7   end
8
9   ...

Armed with this knowledge, changing the validation error behavior is as simple as overriding Action View’s field_error_proc attribute with your own custom Proc. I would suggest doing so in an initializer file.

In Listing 11.1, I changed the setting so that the input fields with validation errors are prefixed with a red ERROR message.

Listing 11.1 Custom Validation Error Display

1 ActionView::Base.field_error_proc =
2    Proc.new do |html_tag,instance|
3      %(<div style="color:red">ERROR</div>) + html_tag
4    end

It has been suggested by many people that it would have been a much better default solution to simply add a field_with_errors CSS class to the input tag itself instead of wrapping it with an extra div tag. Indeed, that would have made many of our lives easier, since an extra div often breaks pixel-perfect layouts. However, since html_tag is already constructed at the time when the field_error_proc is invoked, it is not trivial to modify its contents.

11.2 AssetTagHelper

According to the Rails API docs, this module

provides methods for generating HTML that links views to assets such as images, javascripts, stylesheets, and feeds. These methods do not verify the assets exist before linking to them.

The AssetTagHelper module includes some methods that you will use daily during active Rails development, particularly image_tag.

11.2.1 Head Helpers

Some of the helper methods in this module help you add content to the head element of your HTML document.

11.2.1.1 auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})

Returns a link tag that browsers and news readers can use to autodetect an RSS or ATOM feed. The type can either be :rss (default) or :atom. Control the link options in url_for format using the url_options.

You can modify the link tag itself using the tag_options parameter:

:rel The relation of this link. Defaults to "alternate".

:type Override MIME type (such as "application/atom+xml") that Rails would otherwise generate automatically for you.

:title The title of the link. Defaults to a capitalized type.

Here are examples of usages of auto_discovery_link_tag as shown in the Rails API docs:

 1 auto_discovery_link_tag
 2 # => <link rel="alternate" type="application/rss+xml" title="RSS"
 3 #       href="http://www.currenthost.com/controller/action" />
 4
 5 auto_discovery_link_tag(:atom)
 6 # => <link rel="alternate" type="application/atom+xml" title="ATOM"
 7 #      href="http://www.currenthost.com/controller/action" />
 8
 9 auto_discovery_link_tag(:rss, {action: "feed"})
10 # => <link rel="alternate" type="application/rss+xml" title="RSS"
11 #      href="http://www.currenthost.com/controller/feed" />
12
13 auto_discovery_link_tag(:rss, {action: "feed"}, {title: "My RSS"})
14 # => <link rel="alternate" type="application/rss+xml" title="My RSS"
15 #       href="http://www.currenthost.com/controller/feed" />

11.2.1.2 favicon_link_tag(source='favicon.ico', options={})

Returns a link loading a favicon file. By default, Rails will set the icon to favicon.ico. You may specify a different file in the first argument.

The favicon_link_tag helper accepts an optional options hash that accepts the following:

:rel Specify the relation of this link. Defaults to shortcut icon.

:type Override the autogenerated MIME type. Defaults to image/vnd.microsoft.icon.

1 favicon_link_tag '/myicon.ico'
2 # => <link href="/assets/favicon.ico" rel="shortcut icon"
3 #      type="image/vnd.microsoft.icon" />

11.2.1.3 javascript_include_tag(*sources)

Returns a script tag for each of the sources provided. You can pass in the filename (the .js extension is optional) of JavaScript files that exist in your app/assets/javascripts directory for inclusion into the current page, or you can pass their full path relative to your document root.

1 javascript_include_tag "xmlhr"
2 # => <script src="/assets/xmlhr.js?1284139606"></script>
3
4 javascript_include_tag "common", "/elsewhere/cools"
5 # => <script src="/assets/common.js?1284139606"></script>
6 #    <script src="/elsewhere/cools.js?1423139606"></script>

When the Asset Pipeline is enabled, passing the name of the manifest file as a source will include all JavaScript or CoffeeScript files that are specified within the manifest.

javascript_include_tag "application"


Note

By default, not including the .js extension to a JavaScript source will result in .js being suffixed to the filename. However, this does not play well with JavaScript templating languages, as they have extensions of their own. To rectify this, as of Rails 4.1, setting the option :extname to false will result in the javascript_include_tag helper to not append .js to the supplied source.

javascript_include_tag 'templates.jst', extname: false
# => <script src="/javascripts/templates.jst"></script>


11.2.1.4 javascript_path(source, options = {})

Computes the path to a JavaScript asset in the app/assets/javascripts directory. If the source parameter is provided without an extension, Rails will append .js at the end. A full path (from the document root) will also be appended and used internally by the javascript_include_tag to build the script path output to your markup.

11.2.1.5 stylesheet_link_tag(*sources)

Returns a stylesheet link tag for the sources specified as arguments. If you don’t specify an extension, .css will be appended automatically. Just like other helper methods that take a variable number of arguments plus options, you can pass a hash of options as the last argument and they will be added as attributes to the tag.

 1 stylesheet_link_tag "style"
 2 # => <link href="/stylesheets/style.css" media="screen"
 3 #      rel="Stylesheet" type="text/css" />
 4
 5 stylesheet_link_tag "style", media: "all"
 6 # => <link href="/stylesheets/style.css" media="all"
 7 #      rel="Stylesheet" type="text/css" />
 8
 9 stylesheet_link_tag "random.styles", "/css/stylish"
10 # => <link href="/stylesheets/random.styles" media="screen"
11 #      rel="Stylesheet" type="text/css" />
12 #    <link href="/css/stylish.css" media="screen"
13 #      rel="Stylesheet" type="text/css" />

11.2.1.6 stylesheet_path(source)

Computes the path to a stylesheet asset in the app/assets/stylesheets directory. If the source filename has no extension, .css will be appended. Full paths from the document root will be passed through. Used internally by stylesheet_link_tag to build the stylesheet path.

11.2.2 Asset Helpers

This module also contains a series of helper methods that generate asset-related markup. It’s important to generate asset tags dynamically, because often assets are either packaged together or served up from a different server source than your regular content. Asset helper methods also timestamp your asset source URLs to prevent browser caching problems.

11.2.2.1 audio_path(source)

Computes the path to an audio asset in the public/audios directory, which you would have to add yourself to your Rails project since it’s not generated by default. Full paths from the document root will be passed through. Used internally by audio_tag to build the audio path.

11.2.2.2 audio_tag(source, options = {})

Returns an HTML5 audio tag based on the source argument.

1 audio_tag("sound")
2 # => <audio src="/audios/sound" />
3
4 audio_tag("sound.wav")
5 # => <audio src="/audios/sound.wav" />
6
7 audio_tag("sound.wav", autoplay: true, controls: true)
8 # => <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" />

11.2.2.3 font_path(source, options = {})

Computes the path to a font asset in the app/assets/fonts directory, which you would have to add yourself to your Rails project since it’s not generated by default. Full paths from the document root (beginning with a “/”) will be passed through.

1 font_path("font.ttf") # => /assets/font.ttf
2 font_path("dir/font.ttf") # => /assets/dir/font.ttf
3 font_path("/dir/font.ttf") # => /dir/font.ttf

11.2.2.4 image_path(source)

Computes the path to an image asset in the app/assets/images directory. Full paths from the document root (beginning with a “/”) will be passed through. This method is used internally by image_tag to build the image path.

1 image_path("edit.png")  # => /assets/edit.png
2 image_path("icons/edit.png")  # => /images/icons/edit.png
3 image_path("/icons/edit.png")  # => /icons/edit.png


Courtenay Says ...

The image_tag method makes use of the image_path method that we cover later in the chapter. This helpful method determines the path to use in the tag. You can call a controller “image” and have it work as a resource, despite the seemingly conflicting name, because for its internal use, ActionView aliases the method to path_to_image.


11.2.2.5 image_tag(source, options = {})

Returns an img tag for use in a template. The source parameter can be a full path or a file that exists in your images directory. You can add additional arbitrary attributes to the img tag using the options parameter. The following two options are treated specially:

:alt If no alternate text is given, the filename part of the source is used after being capitalized and stripping off the extension.

:size Supplied as widthxheight so "30x45" becomes the attributes width="30" and height="45". The :size option will fail silently if the value is not in the correct format.

1 image_tag("icon.png")
2 # => <img src="/assets/icon.png" alt="Icon" />
3
4 image_tag("icon.png", size: "16x10", alt: "Edit Entry")
5 # => <img src="/assets/icon.png" width="16" height="10" alt="Edit Entry" />
6
7 image_tag("/photos/dog.jpg", class: 'icon')
8 # => <img src="/photos/icon.gif" alt="Dog" class="icon"/>

11.2.2.6 video_path

Computes the path to a video asset in the public/videos directory, which you would have to add yourself to your Rails project since it’s not generated by default. Full paths from the document root will be passed through. Used internally by video_tag to build the video’s src attribute.

11.2.2.7 video_tag(sources, options = {})

Returns an HTML5 video tag for the sources. If sources is a string, a single video tag will be returned. If sources is an array, a video tag with nested source tags for each source will be returned. The sources can be full paths or files that exists in your public videos directory.

You can add normal HTML video element attributes using the options hash. The options supports two additional keys for convenience and conformance:

:poster Set an image (like a screenshot) to be shown before the video loads. The path is calculated using image_path.

:size Supplied as widthxheight in the same manner as image_tag. The :size option can also accept a stringified number, which sets both width and height to the supplied value.

 1 video_tag("trailer")
 2 # => <video src="/videos/trailer" />
 3
 4 video_tag("trailer.ogg")
 5 # => <video src="/videos/trailer.ogg" />
 6
 7 video_tag("trail.ogg", controls: true, autobuffer: true)
 8 # => <video autobuffer="autobuffer" controls="controls"
 9 #      src="/videos/trail.ogg" />
10
11 video_tag("trail.m4v", size: "16x10", poster: "screenshot.png")
12 # => <video src="/videos/trailer.m4v" width="16" height="10"
13 #      poster="/images/screenshot.png" />
14
15 video_tag(["trailer.ogg", "trailer.flv"])
16 # => <video>
17 #      <source src="trailer.ogg"/>
18 #      <source src="trailer.flv"/>
19 #    </video>

11.2.3 Using Asset Hosts

By default, Rails links to assets on the current host in the public folder, but you can direct Rails to link to assets from a dedicated asset server by setting ActionController::Base.asset_host in a configuration file, typically in config/environments/production.rb so that it doesn’t affect your development environment. For example, you’d define assets.example.com to be your asset host this way:

config.action_controller.asset_host = "assets.example.com"

The helpers we’ve covered take that into account when generating their markup:

1 image_tag("rails.png")
2 # => <img alt="Rails"
3 #        src="http://assets.example.com/images/rails.png?1230601161" />
4
5 stylesheet_link_tag("application")
6 # => <link
7 #     href="http://assets.example.com/stylesheets/application.css?1232285206"
8 #       media="screen" rel="stylesheet" type="text/css" />

Browsers typically open at most two simultaneous connections to a single host. In the worst case scenario, with many asset files, only two files at a time will be downloaded. You can alleviate this bottleneck by using a %d wildcard in your asset_host setting. For example, “assets%d.example.com.” If that wildcard is present, Rails distributes asset requests among the corresponding four hosts: “assets0.example.com,” “assets1.example.com,” and so on. With this trick, browsers will open eight simultaneous connections rather than two.

1 image_tag("rails.png")
2 # => <img alt="Rails"
3 #      src="http://assets0.example.com/images/rails.png?1230601161" />
4
5 stylesheet_link_tag("application")
6 # => <link
7 #     href="http://assets2.example.com/stylesheets/application.css?1232285206"
8 #       media="screen" rel="stylesheet" type="text/css" />

To get this technique working in a production deployment, you can either set up four actual hosts with the same asset content or use wildcard DNS to CNAME the wildcard to a single asset host. You can read more about setting up your DNS CNAME records from your hosting provider. Note that this technique is purely a browser performance optimization and is unrelated to server load balancing.1

1. See http://www.die.net/musings/page_load_time/ for background information.

Alternatively, you can exert more control over the asset host by setting asset_host to a proc like the following:

config.action_controller.asset_host = Proc.new { |source|
  "http://assets#{rand(2) + 1}.example.com"
}

The example generates http://assets1.example.com and http://assets2.example.com randomly. This option is useful, for example, if you need fewer/more than four hosts, custom host names, and so on. As you see, the proc takes a source parameter. That’s a string with the absolute path of the asset with any extensions and timestamps in place—for example, /images/rails.png?1230601161.

 1 config.action_controller.asset_host = Proc.new { |source|
 2   if source.starts_with?('/images')
 3     "http://images.example.com"
 4   else
 5     "http://assets.example.com"
 6   end
 7 }
 8
 9 image_tag("rails.png")
10  # => <img alt="Rails"
11        src="http://images.example.com/images/rails.png?1230601161" />
12
13 stylesheet_link_tag("application")
14 # => <link href="http://assets.example.com/stylesheets/application.css?1232285206"
15          media="screen" rel="stylesheet" type="text/css" />

Alternatively you may ask for a second parameter request, which is particularly useful for serving assets from an SSL-protected page. The following example disables asset hosting for HTTPS connections while still sending assets for plain HTTP requests from asset hosts. If you don’t have SSL certificates for each of the asset hosts, this technique allows you to avoid warnings in the client about mixed media.

1 ActionController::Base.asset_host = Proc.new { |source, request|
2   if request.ssl?
3     "#{request.protocol}#{request.host_with_port}"
4   else
5     "#{request.protocol}assets.example.com"
6   end
7 }

For easier testing and reuse, you can also implement a custom asset host object that responds to call and takes either one or two parameters just like the proc.

config.action_controller.asset_host = AssetHostingWithMinimumSsl.new(
  "http://asset%d.example.com", "https://asset1.example.com"
)

11.2.4 For Plugins Only

A handful of class methods in AssetTagHelper relate to configuration and are intended for use in plugins.

register_javascript_expansion

register_stylesheet_expansion

11.3 AtomFeedHelper

Provides an atom_feed helper to aid in generating ATOM feeds in builder templates.

 1 atom_feed do |feed|
 2   feed.title("My great blog!")
 3   feed.updated(@posts.first.created_at)
 4
 5   @posts.each do |post|
 6     feed.entry(post) do |entry|
 7       entry.title(post.title)
 8       entry.content(post.body, type: 'html')
 9
10       entry.author do |author|
11         author.name("DHH")
12       end
13     end
14   end
15 end

The options for atom_feed are the following:

:language Defaults to "en-US".

:root_url The HTML alternative that this feed is doubling for. Defaults to "/" on the current host.

:url The URL for this feed. Defaults to the current URL.

:id The id for this feed. Defaults to tag:#{request.host},#{options}:#{request.fullpath.split(".")}.

:schema_date The date at which the tag scheme for the feed was first used. A good default is the year you created the feed. See http://feedvalidator.org/docs/error/InvalidTAG.html for more information. If not specified, 2005 is used (as an “I don’t care” value).

:instruct Hash of XML processing instructions in the form of {target => {attribute => value, ...}} or {target => [{attribute => value, ...}, ]}.

Other namespaces can be added to the root element:

 1 atom_feed(
 2   'xmlns:app' => 'http://www.w3.org/2007/app',
 3   'xmlns:openSearch' => 'http://a9.com/-/spec/opensearch/1.1/'
 4   ) do |feed|
 5   feed.title("My great blog!")
 6   feed.updated((@posts.first.created_at))
 7   feed.tag!(openSearch:totalResults, 10)
 8
 9   @posts.each do |post|
10     feed.entry(post) do |entry|
11       entry.title(post.title)
12       entry.content(post.body, type: 'html')
13       entry.tag!('app:edited', Time.now)
14
15       entry.author do |author|
16         author.name("DHH")
17       end
18     end
19   end
20 end

The ATOM spec defines five elements that may directly contain XHTML content if type: 'xhtml' is specified as an attribute:

content

rights

title

subtitle

summary

If any of these elements contain XHTML content, this helper will take care of the needed enclosing div and an XHTML namespace declaration.

1 entry.summary type: 'xhtml' do |xhtml|
2  xhtml.p pluralize(order.line_items.count, "line item")
3  xhtml.p "Shipped to #{order.address}"
4  xhtml.p "Paid by #{order.pay_type}"
5 end

The atom_feed method yields an AtomFeedBuilder instance. Nested elements also yield AtomBuilder instances.

11.4 CacheHelper

This module contains helper methods related to caching fragments of a view. Fragment caching is useful when certain elements of an action change frequently or depend on complicated state, while other parts rarely change or can be shared among multiple parties. The boundaries of a fragment to be cached are defined within a view template using the cache helper method. This topic is covered in detail in the caching section of Chapter 17, “Caching and Performance.”

11.5 CaptureHelper

One of the great features of Rails views is that you are not limited to rendering a single flow of content. Along the way, you can define blocks of template code that should be inserted into other parts of the page during rendering using yield. The technique is accomplished via a pair of methods from the CaptureHelper module.

11.5.0.1 capture(&block)

The capture method lets you capture part of a template’s output (inside a block) and assign it to an instance variable. The value of that variable can subsequently be used anywhere else on the template.

1 - message_html = capture do
2   %div
3     This is a message

I don’t think the capture method is that useful on its own in a template. It’s a lot more useful when you use it in your own custom helper methods. It gives you the ability to write your own helpers that grab template content wrapped using a block. We cover that technique later on in this chapter in the section “Writing Your Own View Helpers.”

11.5.0.2 content_for(name, &block)

We mentioned the content_for method in Chapter 10, “Action View,” in the section “Yielding Content.” It allows you to designate a part of your template as content for another part of the page. It works similarly to its sister method capture (in fact, it uses capture itself). Instead of returning the contents of the block provided to it, it stores the content to be retrieved using yield elsewhere in the template (or, most commonly, in the surrounding layout).

A common example is to insert sidebar content into a layout. In the following example, the link will not appear in the flow of the view template. It will appear elsewhere in the template, wherever yield :navigation_sidebar appears.

1 - content_for :navigation_sidebar do
2   = link_to 'Detail Page', item_detail_path(item)

11.5.0.3 content_for?(name)

Using this method, you can check whether the template will ultimately yield any content under a particular name using the content_for helper method so that you can make layout decisions earlier in the template. The following example clearly illustrates usage of this method by altering the CSS class of the body element dynamically:

1 %body{class: content_for?(:right_col) ? 'one-column' : 'two-column'}
2   = yield
3   = yield :right_col

11.5.0.4 provide(name, content = nil, &block)

The provide helper method works the same way as content_for, except for when used with streaming. When streaming, provide flushes the current buffer straight back to the layout and stops looking for more contents.

If you want to concatenate multiple times to the same buffer when rendering a given template, you should use content_for instead.

11.6 CsrfHelper

The CsrfHelper module only contains one method, named csrf_meta_tags. Including it in the <head> section of your template will output meta tags “csrf-param” and “csrf-token” with the name of the cross-site request forgery protection parameter and token, respectively.

1 %head
2   = csrf_meta_tags

The meta tags “csrf-param” and “csrf-token” are used by Rails to generate dynamic forms that implement nonremote links with :method.

11.7 DateHelper

The DateHelper module is used primarily to create HTML select tags for different kinds of calendar data. It also features one of the longest-named helper methods, a beast peculiar to Rails, called distance_of_time_in_words_to_now.


Lark Says ...

I guess that helper method name was too much of a mouthful, since at some point it was aliased to time_ago_in_words.


11.7.1 The Date and Time Selection Helpers

The following methods help you create form field input tags dealing with date and time data. All of them are prepared for multiparameter assignment to an Active Record object. That’s a fancy way of saying that even though they appear in the HTML form as separate input fields, when they are posted back to the server, it is understood that they refer to a single attribute of the model. That’s some Rails magic for you!

11.7.1.1 date_select(object_name, method, options = {}, html_options = {})

Returns a matched set of three select tags (one each for year, month, and day) preselected for accessing a specified date-based attribute (identified by the method parameter) on an object assigned to the template (identified by object_name).

It’s possible to tailor the selects through the options hash, which accepts all the keys that each of the individual select builders do (like :use_month_numbers for select_month).

The date_select method also takes :discard_year, :discard_month, and :discard_day options, which drop the corresponding select tag from the set of three. Common sense dictates that discarding the month select will also automatically discard the day select. If the day is omitted but not the month, Rails will assume that the day should be the first of the month.

It’s also possible to explicitly set the order of the tags using the :order option with an array of symbols :year, :month, and :day in the desired order. Symbols may be omitted and the respective select tag is not included.

Passing disabled: true as part of the options will make elements inaccessible for change (see Listing 11.2).

Listing 11.2 Examples of date_select

 1 date_select("post", "written_on")
 2
 3 date_select("post", "written_on", start_year: 1995,
 4                                   use_month_numbers: true,
 5                                   discard_day: true,
 6                                   include_blank: true)
 7
 8 date_select("post", "written_on", order: [:day, :month, :year])
 9
10 date_select("user", "birthday",    order: [:month, :day])

If anything is passed in the html_options hash, it will be applied to every select tag in the set.

11.7.1.2 datetime_select(object_name, method, options = {}, html_options = {})

Works exactly like date_select except for the addition of hour and minute select tags. Seconds may be added with the option :include_seconds. Along with the addition of time information come additional discarding options: :discard_hour, :discard_minute, and :discard_seconds.

Setting the ampm option to true returns hours in the AM/PM format.

1 datetime_select("post", "written_on")
2
3 datetime_select("post", "written_on", ampm: true)

11.7.1.3 time_select(object_name, method, options = {}, html_options = {})

Returns a set of select tags (one for hour, minute, and optionally second) preselected for accessing a specified time-based attribute (identified by method) on an object assigned to the template (identified by object_name). You can include the seconds by setting the :include_seconds option to true.

As with datetime_select, setting ampm: true will result in hours displayed in the AM/PM format.

1 time_select("post", "sunrise")
2
3 time_select("post", "written_on", include_seconds: true)
4
5 time_select("game", "written_on", ampm: true)

11.7.2 The Individual Date and Time Select Helpers

Sometimes you need just a particular element of a date or time, and Rails obliges you with a comprehensive set of individual date and time select helpers. In contrast to the date and time helpers that we just looked at, the following helpers are not bound to an instance variable on the page. Instead, they all take a date or time Ruby object as their first parameter. (All of these methods have a set of common options, covered in the following subsection.)

11.7.2.1 select_date(date = Date.current, options = {}, html_options = {})

Returns a set of select tags (one each for year, month, and day) preselected with the date provided (or the current date). It’s possible to explicitly set the order of the tags using the :order option with an array of symbols :year, :month, and :day in the desired order.

select_date(started_at, order: [:year, :month, :day])

11.7.2.2 select_datetime(datetime = Time.current, options = {}, html_options = {})

Returns a set of select tags (one each for year, month, day, hour, and minute), preselected with the datetime. Optionally, setting the include_seconds: true option adds a seconds field. It’s also possible to explicitly set the order of the tags using the :order option with an array of symbols :year, :month, :day, :hour, :minute, and :seconds in the desired order. You can also add character values for the :date_separator and :time_separator options to control visual display of the elements (they default to "/" and ":").

11.7.2.3 select_day(date, options = {}, html_options = {})

Returns a select tag with options for each of the days 1 through 31 with the current day selected. The date can also be substituted for a day value ranging from 1 to 31. If displaying days with a leading zero is your preference, setting the option use_two_digit_numbers to true will accomplish this.

1 select_day(started_at)
2
3 select_day(10)
4
5 select_day(5, use_two_digit_numbers: true)

By default, the field name defaults to day but can be overridden using the :field_name option.

11.7.2.4 select_hour(datetime, options = {}, html_options = {})

Returns a select tag with options for each of the hours 0 through 23, with the current hour selected. The datetime parameter can be substituted with an hour number from 0 to 23. Setting the ampm option to true will result in hours displayed in the AM/PM format. By default, the field name defaults to hour but can be overridden using the :field_name option.

11.7.2.5 select_minute(datetime, options = {}, html_options = {})

Returns a select tag with options for each of the minutes 0 through 59 with the current minute selected. Also can return a select tag with options by minute_step from 0 through 59 with the 00 minute selected. The datetime parameter can be substituted by a seconds value of 0 to 59. By default, the field name defaults to minute but can be overridden using the :field_name option.

11.7.2.6 select_month(date, options = {}, html_options = {})

Returns a select tag with options for each of the months January through December with the current month selected. By default, the month names are presented as user options in the drop-down selection and the month numbers (1 through 12) are used as values submitted to the server.

It’s also possible to use month numbers for the presentation instead of names by setting use_month_numbers: true. To display month numbers with a leading zero, set option :use_two_digit_numbers to true. If you happen to want both numbers and names, set add_month_numbers: true. If you would prefer to show month names as abbreviations, set the :use_short_month option to true. Finally, if you want to use your own month names, set the value of the :use_month_names key in your options to an array of 12 month names.

 1 # Will use keys like "January," "March"
 2 select_month(Date.today)
 3
 4 # Will use keys like "1," "3"
 5 select_month(Date.today, use_month_numbers: true)
 6
 7 # Will use keys like "1 - January," "3 - March"
 8 select_month(Date.today, add_month_numbers: true)
 9
10 # Will use keys like "Jan," "Mar"
11 select_month(Date.today, use_short_month: true)
12
13 # Will use keys like "Januar" "Marts"
14 select_month(Date.today, use_month_names: %w(Januar Februar
15 Marts ...))

By default, the field name defaults to month but can be overridden using the :field_name option.

11.7.2.7 select_second(datetime, options = {}, html_options = {})

Returns a select tag with options for each of the seconds 0 through 59 with the current second selected. The datetime parameter can either be a DateTime object or a second given as a number. By default, the field name defaults to second but can be overridden using the :field_name option.

11.7.2.8 select_time(datetime = Time.current, options = {}, html_options = {})

Returns a set of HTML select tags (one for hour and minute). You can set the :time_separator option to format the output. It’s possible to take an input for sections by setting option :include_seconds to true.

select_time(some_time, time_separator: ':', include_seconds: true)

11.7.2.9 select_year(date, options = {}, html_options = {})

Returns a select tag with options for each of the five years on each side of the current year, which is selected. The five-year radius can be changed using the :start_year and :end_year options. Both ascending and descending year lists are supported by making :start_year less than or greater than :end_year. The date parameter can either be a Date object or a year given as a number.

1 # ascending year values
2 select_year(Date.today, start_year: 1992, end_year: 2007)
3
4 # descending year values
5 select_year(Date.today, start_year: 2005, end_year: 1900)

By default, the field name defaults to year but can be overridden using the :field_name option.

11.7.3 Common Options for Date Selection Helpers

All the select-type methods share a number of common options that are as follows:

:discard_type Set to true if you want to discard the type part of the select name. If set to true, the select_month method would use simply date (which can be overwritten using :prefix) instead of date[month].

:field_name Allows you to override the natural name of a select tag (from day, minute, and so on).

:include_blank Set to true if it should be possible to set an empty date.

:prefix Overwrites the default prefix of date used for the names of the select tags. Specifying birthday would result in a name of birthday[month] instead of date[month] when passed to the select_month method.

:use_hidden Set to true to embed the value of the datetime into the page as an HTML hidden input instead of a select tag.

:disabled Set to true if you want show the select fields as disabled.

:prompt Set to true (for a generic prompt), a prompt string or a hash of prompt strings for :year, :month, :day, :hour, :minute, and :second.

11.7.4 distance_in_time Methods with Complex Descriptive Names

Some distance_in_time methods have really long, complex descriptive names that nobody can ever remember without looking them up—well, at least for the first dozen times or so.

I find the following methods to be a perfect example of the Rails way when it comes to API design. Instead of going with a shorter and necessarily more cryptic alternative, the framework author decided to keep the name long and descriptive. It’s one of those cases where a nonprogrammer can look at your code and understand what it’s doing. Well, probably.

I also find these methods remarkable in that they are part of why people sometimes consider Rails part of the Web 2.0 phenomenon. What other web framework would include ways to humanize the display of timestamps?

11.7.4.1 distance_of_time_in_words(from_time, to_time = 0, include_seconds_or_options = {}, options = {}))

Reports the approximate distance in time between two Time, DateTime, or Date objects or integers as seconds. Set the include_seconds parameter to true if you want more detailed approximations when the distance is less than one minute. The easiest way to show what this method does is via examples:

>> from_time = Time.current

>> helper.distance_of_time_in_words(from_time, from_time + 50.minutes)
=> about 1 hour

>> helper.distance_of_time_in_words(from_time, from_time + 15.seconds)
=> less than a minute

>> helper.distance_of_time_in_words(from_time, from_time + 15.seconds,
     include_seconds: true)
=> less than 20 seconds

>> helper.distance_of_time_in_words(from_time, 3.years.from_now)
=> about 3 years

The Rails API docs ask you to note that Rails calculates 1 year as 365.25 days.

11.7.4.2 distance_of_time_in_words_to_now(from_time, include_seconds_or_options = {})

Works exactly like distance_of_time_in_words except that the to_time is hard-coded to the current time. Usually invoked on created_at or updated_at attributes of your model, followed by the string ago in your template, as in the following example:

1 %strong= comment.user.name
2 %br
3 %small= "#{distance_of_time_in_words_to_now(review.created_at)} ago"

Note, this method is aliased to time_ago_in_words for those who prefer shorter method names.

11.7.5 time_tag(date_or_time, *args, &block)

Introduced in Rails 3.1, the time_tag returns an HTML5 time element for a given date or time. Using the semantic time_tag helper ensures that your date or time within your markup is in a machine-readable format. Setting the option pubdate to true will add the attribute to the tag, indicating that the date or time is a publishing date. The following examples show the output one can expect when using it:

 1 time_tag(Date.current)
 2 # => <time datetime="2013-08-13">August 13, 2013</time>
 3
 4 time_tag(Time.current)
 5 # => <time datetime="2013-08-13T14:58:29Z">August 13, 2013 14:58</time>
 6
 7 time_tag(Time.current, pubdate: true)
 8 # => <time datetime="2013-08-13T15:02:56Z" pubdate="pubdate">August
         13, 2013 15:02</time>

 9
10 = time_tag(Date.current) do
11   %strong Once upon a time
12 # => <time datetime="2013-08-13"><strong>Once upon a time</strong></time>

11.8 DebugHelper

The DebugHelper module only contains one method, named debug. Output it in your template, passing it an object that you want dumped to YAML and displayed in the browser inside PRE tags. Useful for debugging during development but not much else.

11.9 FormHelper

The FormHelper module provides a set of methods for working with HTML forms, especially as they relate to Active Record model objects assigned to the template. Its methods correspond to each type of HTML input fields (such as text, password, select, etc.) available. When the form is submitted, the value of the input fields are bundled into the params that is passed to the controller.

There are two types of form helper methods. The types found in this module are meant to work specifically with Active Record model attributes, and the similarly named versions in the FormTagHelper module are not.


Note

The form helper methods in this section can also be used with non–Active Record models, as long as the model passes the Active Model Lint tests found in module ActiveModel::Lint::Tests. The easiest way to do this is to include the module mixin ActiveModel::Model to your class.


11.9.1 Creating Forms for Models

The core method of this helper is called form_for, and we covered it to some extent in Chapter 3, “REST, Resources, and Rails.” The helper method yields a form object, on which you can invoke input helper methods, omitting their first argument. Usage of form_for leads to succinct form code:

1 = form_for offer do |f|
2   = f.label :version, 'Version'
3   = f.text_field :version
4   %br
5   = f.label :author, 'Author'
6   = f.text_field :author

The form_for block argument is a form builder object that carries the model. Thus the idea is that

= f.text_field :first_name

gets expanded to

= text_field :person, :first_name

If you want the resulting params hash posted to your controller to be named based on something other than the class name of the object you pass to form_for, you can pass an arbitrary symbol to the :as option:

= form_for person, as: :client do |f|

In that case, the call to text_field

= f.text_field :first_name

would get expanded to

= text_field :client, :first_name, object: person

11.9.1.1 form_for Options

In any of its variants, the rightmost argument to form_for is an optional hash of options:

:url The URL the form is submitted to. It takes the same fields you pass to url_for or link_to. In particular you may pass here a named route directly as well. Defaults to the current action.

:namespace A namespace that will be prefixed with an underscore on the generated HTML id of the form.

:html Optional HTML attributes for the form tag.

:builder Optional form builder class (instead of ActionView::Helpers::FormBuilder).

11.9.1.2 Resource-Oriented Style

The preferred way to use form_for is to rely on automated resource identification, which will use the conventions and named routes of that approach instead of manually configuring the :url option.

For example, if post is an existing record to be edited, then the resource-oriented style

= form_for post do |f|

is equivalent to

= form_for post, as: :post, url: post_path(post),
    method: :patch, html: { class: "edit_post",
    id: "edit_post_45" } do |f|

The form_for method also recognizes new records by calling new? on the object you pass to it.

= form_for(Post.new) do |f|

expands to

= form_for post, as: :post, url: posts_path, html: { class: "new_post",
    id: "new_post" } do |f|

The individual conventions can be overridden by supplying an object argument plus :url, :method and/or :html options.

= form_for(post, url: super_post_path(post)) do |f|

You can create forms with namespaced routes by passing an array as the first argument, as in the following example, which would map to a admin_post_url:

= form_for([:admin, post]) do |f|

The following example is the equivalent (old-school) version of form_tag, which doesn’t use a yielded form object and explicitly names the object being used in the input fields:

1 = form_tag people_path do
2   .field
3     = label :person, :first_name
4     = text_field :person, :first_name
5   .field
6     = label :person, :last_name
7     = text_field :person, :last_name
8   .buttons
9     = submit_tag 'Create'

The first version has slightly less repetition (remember your DRY principle) and is almost always going to be more convenient as long as you’re rendering Active Record objects.

11.9.1.3 Variables Are Optional

If you explicitly specify the object name parameter for input fields rather than letting them be supplied by the form, keep in mind that it doesn’t have to match a live object instance in scope for the template. Rails won’t complain if the object is not there. It will simply put blank values in the resulting form.

11.9.1.4 Rails-Generated Form Conventions

The HTML generated by the form_for invocations in the preceding example is characteristic of Rails forms and follows specific naming conventions.

In case you’re wondering, the authenticity_token hidden field with gibberish up near the top of the form has to do with protection against malicious cross-site request forgery (CSRF) attacks.

 1 <form accept-charset="UTF-8" action="/people" method="post">
 2   <div style="margin:0;padding:0;display:inline">
 3     <input name="utf8" type="hidden" value="&#x2713;" />
 4     <input name="authenticity_token" type="hidden"
 5            value="afl+6u3J/2meoHtve69q+tD9gPc3/QUsHCqPh85Z4WU=" /></div>
 6     <div class='field'>
 7       <label for="person_first_name">First name</label>
 8       <input id="person_first_name" name="person[first_name]" type="text" />
 9     </div>
10     <div class='field'>
11       <label for="person_last_name">Last name</label>
12       <input id="person_last_name" name="person[last_name]" type="text" />
13     </div>
14     <div class='buttons'>
15       <input name="commit" type="submit" value="Create" />
16     </div>
17   </form>

When this form is submitted, the params hash will look like the following example (using the format reflected in your development log for every request):

Parameters: {"utf8"=>"✓",
"authenticity_token"=>"afl+6u3J/2meoHtve69q+tD9gPc3/QUsHCqPh85Z4WU=",
"person"=>{"first_name"=>"William", "last_name"=>"Smith"},
"commit"=>"Create"}

As you can see, the params hash has a nested "person" value, which is accessed using params[:person] in the controller. That’s pretty fundamental Rails knowledge, and I’d be surprised if you didn’t know it already. I promise we won’t rehash much more basic knowledge after the following section.

11.9.1.5 Displaying Existing Values

If you were editing an existing instance of Person, that object’s attribute values would have been filled into the form. That’s also pretty fundamental Rails knowledge. What about if you want to edit a new model object instance, prepopulated with certain values? Do you have to pass the values as options to the input helper methods? No. Since the form helpers display the values of the model’s attributes, it would simply be a matter of initializing the object with the desired values in the controller, as follows:

1 # Using the gem decent exposure
2 expose(:person) do
3   if person_id = (params[:person_id] || params[:id])
4     Person.find(person_id)
5   else
6     # Set default values that you want to appear in the form
7     Person.new(first_name: 'First', last_name: 'Last')
8   end
9 end

Since you’re only using new, no record is persisted to the database, and your default values magically appear in the input fields.

11.9.2 How Form Helpers Get Their Values

A rather important lesson to learn about Rails form helper methods is that the value they display comes directly from the database prior to meddling by the developer. Unless you know what you’re doing, you may get some unexpected results if you try to override the values to be displayed in a form.

Let’s illustrate with a simple LineItem model, which has a decimal rate attribute (by merits of a rate column in its database table). We’ll override its implicit rate accessor with one of our own:

1 class LineItem < ActiveRecord::Base
2   def rate
3     "A RATE"
4   end
5 end

In normal situations, the overridden accessor is hiding access to the real rate attribute, as we can illustrate using the console.

>> li = LineItem.new
=> #<LineItem ...>
>> li.rate
=> "A RATE"

However, suppose you were to compose a form to edit line items using form helpers:

1 = form_for line_item do |f|
2   = f.text_field :rate

You would find that it works normally, as if that overridden rate accessor doesn’t exist. The fact is that Rails form helpers use special methods named attribute_before_type_cast (which are covered in Chapter 5, “Working with Active Record”). The preceding example would use the method rate_before_type_cast and bypass the overriding method we defined.

11.9.3 Integrating Additional Objects in One Form

The fields_for helper method creates a scope around a specific model object like form_for but doesn’t create the form tags themselves. Neither does it have an actual HTML representation as a div or fieldset. The fields_for method is suitable for specifying additional model objects in the same form, particularly associations of the main object being represented in the form.

11.9.3.1 Generic Examples

The following simple example represents a person and its associated permissions.

1 = form_for person do |f| %>
2   First name:
3   = f.text_field :first_name
4   Last name:
5   = f.text_field :last_name
6   .permissions
7     = fields_for person.permission do |permission_fields|
8       Admin?:
9       = permission_fields.check_box :admin

11.9.3.2 Nested Attributes Examples

When the object belonging to the current scope has a nested attribute writer for a certain attribute, fields_for will yield a new scope for that attribute. This allows you to create forms that set or change the attributes of a parent object and its associations in one go.

Nested attribute writers are normal setter methods named after an association. The most common way of defining these writers is either by declaring accepts_nested_attributes_for in a model definition or by defining a method with the proper name. For example, the attribute writer for the association :address is called address_attributes=.

Whether a one-to-one or one-to-many style form builder will be yielded depends on whether the normal reader method returns a single object or an array of objects. Consider a simple Ruby Person class that returns a single Address from its address reader method and responds to the address_attributes= writer method:

1 class Person
2   def address
3     @address
4   end
5
6   def address_attributes=(attributes)
7     # Process the attributes hash
8   end
9 end

This model can now be used with a nested fields_for, like the following:

1 = form_for person do |f|
2   = f.fields_for :address do |address_fields|
3     Street:
4     = address_fields.text_field :street
5     Zip code:
6     = address_fields.text_field :zip_code

When address is already an association on a Person, you can use accepts_nested_attributes_for to define the writer method for you, like the following:

1 class Person < ActiveRecord::Base
2   has_one :address
3   accepts_nested_attributes_for :address
4 end

If you want to destroy the associated model through the form, you have to enable it first using the :allow_destroy option for accepts_nested_attributes_for, like the following:

1 class Person < ActiveRecord::Base
2   has_one :address
3   accepts_nested_attributes_for :address, allow_destroy: true
4 end

Now when you use a check box form element specially named _destroy with a value that evaluates to true, the logic generated by accepts_nested_attribute_for will destroy the associated model. (This is a super useful technique for list screens that allow deletion of multiple records at once using check boxes.)

1 = form_for person do |f|
2   = f.fields_for :address do |address_fields|
3     Delete this address:
4     = address_fields.check_box :_destroy

11.9.3.3 fields_for with One-to-Many Associations

Consider a Person class that returns an array of Project instances from the projects reader method and responds to the projects_attributes= writer method:

1 class Person < ActiveRecord::Base
2   def projects
3     [@project1, @project2]
4   end
5
6   def projects_attributes=(attributes)
7     # Process the attributes hash.
8   end
9 end

This model can now be used with a nested fields_for helper method in a form. The block given to the nested fields_for call will be repeated for each instance in the collection automatically:

1 = form_for person do |f|
2   = f.fields_for :projects do |project_fields|
3     .project
4       Name:
5       = project_fields.text_field :name

It’s also possible to specify the instance to be used by doing the iteration yourself. The symbol passed to fields_for refers to the reader method of the parent object of the form, but the second argument contains the actual object to be used for fields:

1 = form_for person do |f|
2   - person.projects.select(&:active?).each do |project|
3     = f.fields_for :projects, project do |project_fields|
4       .project
5         Name:
6         = project_fields.text_field :name

Since fields_for also understands a collection as its second argument in that situation, you can shrink that last example to the following code. Just inline the projects collection:

1 = form_for person do |f|
2   = f.fields_for :projects, projects.select(&:active?) do |project_fields|
3       .project
4         Name:
5         = project_fields.text_field :name

If in our example Person was an Active Record model and projects was one of its has_many associations, then you could use accepts_nested_attributes_for to define the writer method for you:

1 class Person < ActiveRecord::Base
2   has_many :projects
3   accepts_nested_attributes_for :projects
4 end

As with using accepts_nested_attributes_for with a belongs_to association, if you want to destroy any of the associated models through the form, you have to enable it first using the :allow_destroy option:

1 class Person < ActiveRecord::Base
2   has_many :projects
3   accepts_nested_attributes_for :projects, allow_destroy: true
4 end

This will allow you to specify which models to destroy in the attributes hash by adding a boolean form element named _destroy.

1  = form_for person do |form|
2    = form.fields_for :projects do |project_fields|
3     Delete this project
4      = project_fields.check_box :_destroy

11.9.3.4 Saving Nested Attributes

Nested records are updated on save, even when the intermediate parent record is unchanged. For example, consider the following model code:

 1 class Project < ActiveRecord::Base
 2   has_many :tasks
 3   accepts_nested_attributes_for :tasks
 4 end
 5
 6 class Task < ActiveRecord::Base
 7   belongs_to :project
 8   has_many :assignments
 9   accepts_nested_attributes_for :assignments
10 end
11
12 class Assignment < ActiveRecord::Base
13   belongs_to :task
14 end

The following spec snippet illustrates nested saving:

 1 # Setup project, task, and assignment objects...
 2 project.update(name: project.name,
 3                tasks_attributes: [{
 4                                     id: task.id,
 5                                     name: task.name,
 6                                     assignments_attributes: [
 7                                       {
 8                                         id: assignment.id,
 9                                         name: 'Paul'
10                                     }]
11                }]
12
13 assignment.reload
14 expect(assignment.name).to eq('Paul')

11.9.4 Customized Form Builders

Under the covers, the form_for method uses a class named ActionView::Helpers::FormBuilder. An instance of it is yielded to the form block. Conveniently, you can subclass it in your application to override existing or define additional form helpers.

For example, let’s say you made a builder class to automatically add labels to form inputs when text_field is called. You’d enable it with the :builder option like the following:

= form_for person, builder: LabelingFormBuilder do |f|

Instructions on making custom form builder classes would fill its own chapter, but one could view the source of some popular Rails form builders such as SimpleForm2 and formtasic3 to learn more.

2. https://github.com/plataformatec/simple_form

3. https://github.com/justinfrench/formtastic

11.9.5 Form Inputs

For each if these methods, there is a similarly named form builder method that omits the object_name parameter.

11.9.5.1 check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")

This helper gives you an extra hidden input field to ensure that a false value is passed even if the check box is unchecked.

check_box('timesheet', 'approved')
# => <input name="timesheet[approved]" type="hidden" value="0"/>
#    <input checked="checked" type="checkbox" id="timesheet_approved"
#      name="timesheet[approved]" value="1" />

11.9.5.2 color_field(object_name, method, options = {})

Creates a color input field that allows the setting of a color via hex values. The default value of a color_field is set to #000000.

color_field(:car, :paint_color)
# => <input id="car_paint_color" name="car[paint_color]" type="color"
#      value="#000000" />"

This method is otherwise identical to text_field.

11.9.5.3 date_field(object_name, method, options = {})

Creates a date input field. If an object is provided to the helper, it calls to_date on it to attempt setting the default value.

date_field(:person, :birthday)
# => <input id="person_birthday" name="person[birthday]" type="date" />

To override the default value, pass a string in the format YYYY-MM-DD to the option :value. This method is otherwise identical to text_field.

11.9.5.4 datetime_field(object_name, method, options = {})

Creates an input field of type “datetype,” which accepts time in UTC. If a DateTime or ActiveSupport::TimeWithZone instance is provided to the helper, it calls strftime with “%Y-%m-%dT%T.%L%z” on the object’s value to attempt setting a default value.

datetime_field(:post, :publish_at)
# => <input id="post_publish_at" name="post[publish_at]" type="-
         datetime" />

The datetime_field accepts options :min, :max, which allow setting the minimum and maximum acceptable values, respectively.

datetime_field(:invoice, :invoiced_on,
  min: Time.current.beginning_of_year,
  max: Time.current.end_of_year)
# => <input id="invoice_invoiced_on" max="2013-12-31T23:59:59.999+0000"
#      min="2013-01-01T00:00:00.000+0000" name="invoice[invoiced_on]"
#      type="datetime" />

To override the default value, pass a string in the format “%Y-%m-%dT%T.%L%z” to the option :value. This method is otherwise identical to text_field.

11.9.5.5 datetime_local_field(object_name, method, options = {})

Creates an input field of type “datetime-local.” This method is otherwise identical to datetime_field, except that the value used is local over UTC. If a DateTime or ActiveSupport::TimeWithZone instance is provided to the helper, it calls strftime with “%Y-%m-%dT%T” on the object’s value to attempt setting a default value.

11.9.5.6 email_field(object_name, method, options = {})

Creates an email input field. This method is otherwise identical to text_field.

11.9.5.7 file_field(object_name, method, options = {})

Creates a file upload field and automatically adds multipart: true to the enclosing form. See file_field_tag for details.

11.9.5.8 hidden_field(object_name, method, options = {})

Creates a hidden field, with parameters similar to text_field.

11.9.5.9 label(object_name, method, content_or_options = nil, options = nil, &block)

Creates a label tag with the for attribute pointed at the specified input field.

label('timesheet', 'approved')
# => <label for="timesheet_approved">Approved</label>
label('timesheet', 'approved', 'Approved?')
# => <label for="timesheet_approved">Approved?</label>

Many of us like to link labels to input fields by nesting. (Many would say that’s the correct usage of labels.) As of Rails 3, the label helper accepts a block so that nesting is possible and works as would be expected. As a result, instead of having to do

= f.label :terms, "<span>Accept #{link_to 'Terms', terms_path}</span>"

you can do the much more elegant and maintainable

= f.label :terms do
    %span Accept #{link_to "Terms", terms_path}

11.9.5.10 month_field(object_name, method, options = {})

Creates an input field of type “month” without any time zone information. A month is represented by four digits for the year, followed by a hyphen and ending with two digits representing the month (e.g., 2013-08).

If a DateTime or ActiveSupport::TimeWithZone instance is provided to the helper, it calls strftime with “%Y-%m” on the object’s value to attempt setting a default value.

month_field(:user, :born_on)
# => <input id="user_born_on" name="user[born_on]" type="month" />

To override the default value, pass a string in the format “%Y-%m” to the option :value. This method is otherwise identical to datetime_field.

11.9.5.11 number_field(object_name, method, options = {})

Creates a number input field. This method is otherwise identical to text_field with the following additional options:

:min The minimum acceptable value.

:max The maximum acceptable value.

:in A range specifying the :min and :max values.

:step The acceptable value granularity.

11.9.5.12 password_field(object_name, method, options = {})

Creates a password input field. This method is otherwise identical to text_field but renders with a nil value by default for security reasons. If you want to prepopulate the user’s password, you can do something like the following:

password_field(:user, :password, value: user.password)

11.9.5.13 radio_button(object_name, method, tag_value, options = {})

Creates a radio button input field. Make sure to give all your radio button options user the same name so that the browser will consider them linked.

= radio_button(:post, :category, :rails)
= radio_button(:post, :category, :ruby)

11.9.5.14 range_field(object_name, method, options = {})

Creates a range input field. This method is otherwise identical to number_field.

11.9.5.15 search_field(object_name, method, options = {})

Creates a search input field. This method is otherwise identical to text_field.

11.9.5.16 telephone_field(object_name, method, options = {})

Creates a telephone input field. This method is otherwise identical to text_field and is aliased as phone_field.

11.9.5.17 submit(value = nil, options = {})

Creates a submit button with the text value as the caption. The option :disable_with can be used to provide a name for disabled versions of the submit button.

11.9.5.18 text_area(object_name, method, options = {})

Creates a multiline text input field (the textarea tag). The :size option lets you easily specify the dimensions of the text area instead of having to resort to explicit :rows and :cols options.

text_area(:comment, :body, size: "25x10")
# => <textarea name="comment[body]" id="comment_body" cols="25" rows="10">
#    </textarea>

11.9.5.19 text_field(object_name, method, options = {})

Creates a standard text input field.

11.9.5.20 time_field(object_name, method, options = {})

Creates an input field of type “time.” If a DateTime or ActiveSupport::TimeWithZone instance is provided to the helper, it calls strftime with “%T.%L” on the object’s value to attempt setting a default value.

time_field(:task, :started_at)
# => <input id="task_started_at" name="task[started_at]" type="time" />

To override the default value, pass a string in the format “%T.%L” to the option :value. This method is otherwise identical to datetime_field.

11.9.5.21 url_field(object_name, method, options = {})

Creates an input field of type “url.” This method is otherwise identical to text_field.

11.9.5.22 week_field(object_name, method, options = {})

Creates an input field of type “week.” If a DateTime or ActiveSupport::TimeWithZone instance is provided to the helper, it calls strftime with “%Y-W%W” on the object’s value to attempt setting a default value.

week_field(:task, :started_at)
# => <input id="task_started_at" name="task[started_at]" type="week" />

To override the default value, pass a string in the format “%Y-W%W” to the option :value. This method is otherwise identical to datetime_field.

11.10 FormOptionsHelper

The methods in the FormOptionsHelper module are all about helping you work with HTML select elements by giving you ways to turn collections of objects into option tags.

11.10.1 Select Helpers

The following methods help you to create select tags based on a pair of object and attribute identifiers.

11.10.1.1 collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})

Returns both select and option tags for the given object and method using options_from_collection_for_select (also in this module) to generate the list of option tags from the collection parameter.

11.10.1.2 grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})

Returns select, optgroup, and option tags for the given object and method using option_groups_from_collection_for_select (covered later in this chapter).

11.10.1.3 select(object, method, collection, value_method, text_method, options = {}, html_options = {})

Creates a select tag and a series of contained option tags for the provided object and attribute. The value of the attribute currently held by the object (if any) will be selected, provided that the object is available (not nil). See options_for_select section for the required format of the choices parameter.

Here’s a small example where the value of @post.person_id is 1:

1 = select(:post, :person_id,
2     Person.all.collect { |p| [ p.name, p.id ] },
3     { include_blank: true })

Executing that helper code would generate the following HTML output:

1 <select id="post_person_id" name="post[person_id]">
2   <option value=""></option>
3   <option value="1" selected="selected">David</option>
4   <option value="2">Sam</option>
5   <option value="3">Tobias</option>
6 </select>

If necessary, specify selected: value to explicitly set the selection or selected: nil to leave all options unselected. The include_blank: true option inserts a blank option tag at the beginning of the list so that there is no preselected value. Also, one can disable specific values by setting a single value or an array of values to the :disabled option.

11.10.1.4 time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})

Returns select and option tags for the given object and method, using time_zone_options_for_select to generate the list of option tags.

In addition to the :include_blank option documented in the preceding section, this method also supports a :model option, which defaults to ActiveSupport::TimeZone. This may be used to specify a different time zone model object.

Additionally, setting the priority_zones parameter with an array of ActiveSupport::TimeZone objects will list any specified priority time zones above any other.

 1 time_zone_select(:user, :time_zone, [
 2   ActiveSupport::TimeZone['Eastern Time (US & Canada)'],
 3   ActiveSupport::TimeZone['Pacific Time (US & Canada)']
 4 ])
 5 # => <select id="user_time_zone" name="user[time_zone]">
 6 #      <option value="Eastern Time (US & Canada)">
 7 #        (GMT-05:00) Eastern Time (US & Canada)
 8 #      </option>
 9 #      <option value="Pacific Time (US & Canada)">
10 #        (GMT-08:00) Pacific Time (US & Canada)
11 #      </option>
12 #      <option disabled="disabled" value="">-------------</option>
13 #      <option value="American Samoa">(GMT-11:00) American Samoa</option>
14 #      ...

Finally, setting the option :default to an instance of ActiveSupport::TimeZone sets the default selected value if none was set.

11.10.2 Check Box/Radio Helpers

The following methods create input tags of type “checkbox” or “radio” based on a collection.

11.10.2.1 collection_check_boxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)

The form helper collection_check_boxes creates a collection of check boxes and associated labels based on a collection.

To illustrate, assuming we have a Post model that has multiple categories, using the collection_check_boxes helper, we can add the ability to set the category_ids of the post:

1 collection_check_boxes(:post, :category_ids, Category.all, :id, :name)
2 # => <input id="post_category_ids_1" name="post[category_ids][]"
3 #      type="checkbox" value="1" />
4 #    <label for="post_category_ids_1">Ruby on Rails</label>
5 #    <input id="post_category_ids_2" name="post[category_ids][]"
6 #      type="checkbox" value="2" />
7 #    <label for="post_category_ids_2">Ruby</label>
8 #    ...

If one wanted to change the way the labels and check boxes are rendered, passing a block will yield a builder:

1 collection_check_boxes(:post, :category_ids, Category.all,
2   :id, :name) do |item|
3   item.label(class: 'check-box') { item.check_box(class:
         'check-box') }
4 end

The builder also has access to methods object, text, and value of the current item being rendered.

11.10.2.2 collection_radio_buttons(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)

The form helper collection_radio_buttons creates a collection of radio buttons and associated labels based on a collection. It is predominately used to set an individual value, such as a belongs_to relationship on a model.


Kevin Says ...

Use collection_radio_buttons with a collection that only has a handful of items unless you want your page to be polluted with radio buttons. Fallback to a collection_select for a large collection.

1 collection_radio_buttons(:post, :author_id, Author.all, :id, :name)
2 # => <input id="post_author_1" name="post[author_id][]"
3 #      type="radio" value="1" />
4 #    <label for="post_author_1">Obie</label>
5 #    <input id="post_author_2" name="post[author_id][]"
6 #      type="radio" value="2" />
7 #    <label for="post_author_2">Kevin</label>
8 #     ...


Similar to the collection_check_boxes helper, if one wanted to change the way the labels and radio buttons are rendered, passing a block will yield a builder:

1 collection_radio_buttons(:post, :author_id,
2   Author.all, :id, :name) do |item|
3   item.label(class: 'radio-button') {
4     item.radio_button(class: 'radio-button')
5   }
6 end

The builder also has access to methods object, text, and value of the current item being rendered.

11.10.3 Option Helpers

For all the following methods, only option tags are returned, so you have to invoke them from within a select helper or otherwise wrap them in a select tag.

11.10.3.1 grouped_options_for_select(grouped_options, selected_key = nil, options = {})

Returns a string of option tags, like options_for_select, but surrounds them with optgroup tags.

11.10.3.2 option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)

Returns a string of option tags, like options_from_collection_for_select, but surrounds them with optgroup tags. The collection should return a subarray of items when calling group_method on it. Each group in the collection should return its own name when calling group_label_method. The option_key_method and option_value_method parameters are used to calculate option tag attributes.

It’s probably much easier to show in an example than to explain in words.

option_groups_from_collection_for_select(@continents, :countries,
  :continent_name, :country_id, :country_name, @selected_country.id)

This example could output the following HTML:

 1  <optgroup label="Africa">
 2    <option value="1">Egypt</option>
 3    <option value="4">Rwanda</option>
 4    ...
 5  </optgroup>
 6  <optgroup label="Asia">
 7    <option value="3" selected="selected">China</option>
 8    <option value="12">India</option>
 9    <option value="5">Japan</option>
10    ...
11  </optgroup>

For the sake of clarity, here are the model classes reflected in the example:

 1 class Continent
 2   def initialize(name, countries)
 3     @continent_name = name; @countries = countries
 4   end
 5
 6   def continent_name
 7     @continent_name
 8   end
 9
10   def countries
11     @countries
12   end
13 end
14
15 class Country
16   def initialize(id, name)
17     @id, @name = id, name
18   end
19
20   def country_id
21     @id
22   end
23
24   def country_name
25     @name
26   end
27 end

11.10.3.3 options_for_select(container, selected = nil)

Accepts a container (hash, array, or anything else enumerable) and returns a string of option tags. Given a container where the elements respond to first and last (such as a two-element array), the “lasts” serve as option values and the “firsts” as option text. It’s not too hard to put together an expression that constructs a two-element array using the map and collect iterators.

For example, assume you have a collection of businesses to display and you’re using a select field to allow the user to filter based on the category of the businesses. The category is not a simple string; in this example, it’s a proper model related to the business via a belongs_to association:

 1 class Business < ActiveRecord::Base
 2   belongs_to :category
 3 end
 4
 5 class Category < ActiveRecord::Base
 6   has_many :businesses
 7
 8   def <=>(other)
 9     ...
10   end
11 end

A simplified version of the template code for displaying that collection of businesses might look like the following:

- opts = businesses.map(&:category).collect { |c| [c.name, c.id] }
= select_tag(:filter, options_for_select(opts, params[:filter]))

The first line puts together the container expected by options_for_select by first aggregating the category attributes of the businesses collection using map and the nifty &:method syntax. The second line generates the select tag using those options (covered later in the chapter). Realistically, you want to massage that category list a little more so that it is ordered correctly and does not contain duplicates:

... businesses.map(&:category).uniq.sort.collect {...

Particularly with smaller sets of data, it’s perfectly acceptable to do this level of data manipulation in Ruby code. And of course, you probably don’t want to ever shove hundreds or especially thousands of rows in a select tag, making this technique quite useful. Remember to implement the spaceship method in your model if you need it to be sortable by the sort method.

Also, it’s worthwhile to experiment with eager loading in these cases so you don’t end up with an individual database query for each of the objects represented in the select tag. In the case of our example, the controller would populate the businesses collection using code like this:

expose(:businesses) do
  Business.where(...).includes(:category)
end

Hashes are turned into a form acceptable to options_for_select automatically—the keys become firsts and values become lasts.

If selected parameter is specified (with either a value or an array of values for multiple selections), the matching last or element will get the selected attribute:

 1 options_for_select([["Dollar", "$"], ["Kroner", "DKK"]])
 2 # => <option value="$">Dollar</option>
 3 #    <option value="DKK">Kroner</option>
 4
 5 options_for_select([ "VISA", "MasterCard" ], "MasterCard")
 6 # => <option>VISA</option>
 7 #    <option selected="selected">MasterCard</option>
 8
 9 options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40")
10 # => <option value="$20">Basic</option>
11 #    <option value="$40" selected="selected">Plus</option>
12
13 >> options_for_select([ "VISA", "MasterCard", "Discover" ],
14                       ["VISA", "Discover"])
15 # => <option selected="selected">VISA</option>
16 #    <option>MasterCard</option>
17 #    <option selected="selected">Discover</option>

A lot of people have trouble getting this method to correctly display their selected item. Make sure that the value you pass to selected matches the type contained in the object collection of the select; otherwise, it won’t work. In the following example, assuming price is a numeric value, without the to_s, selection would be broken, since the values passed as options are all strings:

1 options_for_select({ "Basic" => "20", "Plus" => "40" }, price.to_s)
2 # => <option value="20">Basic</option>
3 #    <option value="40" selected="selected">Plus</option>

11.10.3.4 options_from_collection_for_select (collection, value_method, text_method, selected=nil)

Returns a string of option tags that have been compiled by iterating over the collection and assigning the result of a call to the value_method as the option value and the text_method as the option text. If selected is specified, the element returning a match on value_method will get preselected.

1 options_from_collection_for_select(Person.all, :id, :name)
2 # => <option value="1">David</option>
3      <option value="2">Sam</option>
4      ...

11.10.3.5 time_zone_options_for_select (selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone)

Returns a string of option tags for pretty much any time zone in the world. Supply a ActiveSupport::TimeZone name as selected to have it preselected. You can also supply an array of ActiveSupport::TimeZone objects as priority_zones so that they will be listed above the rest of the (long) list. TimeZone.us_zones is a convenience method that gives you a list of the US time zones only.

The selected parameter must be either nil or a string that names an ActiveSupport::TimeZone (covered in Appendix B).

11.11 FormTagHelper

The following helper methods generate HTML form and input tags based on explicit naming and values, contrary to the similar methods present in FormHelper, which require association to an Active Record model instance. All of these helper methods take an options hash, which may contain special options or simply additional attribute values that should be added to the HTML tag being generated.

11.11.0.1 button_tag(content_or_options = nil, options = nil, &block)

Creates a button element that can be used to define a submit, reset, or generic button to be used with JavaScript.

1 button_tag('Submit')
2 # => <button name="button" type="submit">Submit</button>
3
4 button_tag('Some call to action',type: 'button')
5 # => <button name="button" type="button">Some call to action</button>

11.11.0.2 check_box_tag(name, value = "1", checked = false, options = {})

Creates a check box input field. Unlike its fancier cousin, check_box in FormHelper, this helper does not give you an extra hidden input field to ensure that a false value is passed even if the check box is unchecked.

1 check_box_tag('remember_me')
2 # => <input id="remember_me" name="remember_me" type="checkbox" value="1"/>
3
4 check_box_tag('remember_me', 1, true)
5 # => <input checked="checked" id="remember_me" name="remember_me"
6 #      type="checkbox" value="1" />

11.11.0.3 color_field_tag(name, value = nil, options = {})

Creates a color input field that allows the setting of a color via hex values. This method is otherwise identical to text_field_tag.

11.11.0.4 date_field_tag(name, value = nil, options = {})

Creates a date input field. This method is otherwise identical to text_field_tag.

11.11.0.5 datetime_field_tag(name, value = nil, options = {})

Creates a datetime input field, which accepts time in UTC. This method is otherwise identical to text_field_tag with the following additional options:

:min The minimum acceptable value.

:max The maximum acceptable value.

:step The acceptable value granularity.

11.11.0.6 datetime_local_field_tag(name, value = nil, options = {})

Creates an input field of type “datetime-local.” This method is otherwise identical to datetime_field_tag, except that the value is not in UTC.

11.11.0.7 email_field_tag(name, value = nil, options = {})

Creates an email input field. This method is otherwise identical to text_field_tag.

11.11.0.8 field_set_tag(legend = nil, options = nil, &block)

Wraps the contents of the given block in a fieldset tag and optionally gives it a legend tag.

11.11.0.9 file_field_tag(name, options = {})

Creates a file upload field. Remember to set your HTML form to multipart or file uploads will mysteriously not work:

1 = form_tag '/upload', multipart: true do
2   = label_tag :file, 'File to Upload'
3   = file_field_tag :file
4   = submit_tag

The controller action will receive a File object pointing to the uploaded file as it exists in a tempfile on your system. The processing of an uploaded file is beyond the scope of this book. If you’re smart, you’ll use Jonas Nicklas’s excellent CarrierWave gem instead of reinventing the wheel.4

4. https://github.com/carrierwaveuploader/carrierwave

11.11.0.10 form_tag(url_for_options = {}, options = {}, &block)

Starts a form tag, with its action attribute set to the URL passed as the url_for_options parameter.

The :method option defaults to POST. Browsers handle HTTP GET and POST natively; if you specify “patch” or “delete” or if any other HTTP verb is used, a hidden input field will be inserted with the name _method and a value corresponding to the method supplied. The Rails request dispatcher understands the _method parameter, which is the basis for the RESTful techniques you learned in Chapter 3, “REST, Resources, and Rails.”

The :multipart option allows you to specify that you will be including file-upload fields in the form submission and the server should be ready to handle those files accordingly.

The :authenticity_token option is used only if you need to pass a custom authenticity token string or want to disable it by setting the option to false.

Setting the option :remote to true will allow the unobtrusive JavaScript drivers to take control of the submit behavior (covered in Chapter 19, “Ajax on Rails”).

 1 form_tag('/posts')
 2 # => <form action="/posts" method="post">
 3
 4 >> form_tag('/posts/1', method: :patch)
 5 # => <form action="/posts/1" method="post">
 6 #      <input name="_method" type="hidden" value="patch" />
 7 #      ...
 8
 9 form_tag('/upload', multipart: true)
10 # => <form action="/upload" method="post" enctype="multipart/form-data">

You might note that all parameters to form_tag are optional. If you leave them off, you’ll get a form that posts back to the URL that it came from—a quick and dirty solution that I use quite often when prototyping or experimenting. To quickly set up a controller action that handles postbacks, just include an if/else condition that checks the request method—something like the following:

1 def add
2   if request.post?
3     # handle the posted params
4     redirect_to :back
5   end
6 end

Notice that if the request is a post, I handle the form params and then redirect back to the original URL (using redirect_to :back). Otherwise, execution simply falls through and would render whatever template is associated with the action.

11.11.0.11 hidden_field_tag(name, value = nil, options = {})

Creates a hidden field with parameters similar to text_field_tag.

11.11.0.12 image_submit_tag(source, options = {})

Displays an image that, when clicked, will submit the form. The interface for this method is the same as its cousin image_tag in the AssetTagHelper module.

Image input tags are popular replacements for standard submit tags because they make an application look fancier. They are also used to detect the location of the mouse cursor on click—the params hash will include x and y data.

11.11.0.13 label_tag(name = nil, content_or_options = nil, options = nil, &block)

Creates a label tag with the for attribute set to name.

11.11.0.14 month_field_tag(name, value = nil, options = {})

Creates an input field of type “month.” This method is otherwise identical to text_field_tag with the following additional options:

:min The minimum acceptable value.

:max The maximum acceptable value.

:step The acceptable value granularity.

11.11.0.15 number_field_tag(name, value = nil, options = {})

Creates a number input field. This method is otherwise identical to text_field_tag with the following additional options:

:min The minimum acceptable value.

:max The maximum acceptable value.

:in A range specifying the :min and :max values.

:step The acceptable value granularity.

11.11.0.16 password_field_tag(name = "password", value = nil, options = {})

Creates a password input field. This method is otherwise identical to text_field_tag.

11.11.0.17 radio_button_tag(name, value, checked = false, options = {})

Creates a radio button input field. Make sure to give all your radio button options the same name so the browser will consider them linked.

11.11.0.18 range_field_tag(name, value = nil, options = {})

Creates a range input field. This method is otherwise identical to number_field_tag.

11.11.0.19 search_field_tag(name, value = nil, options = {})

Creates a search input field. This method is otherwise identical to text_field_tag.

11.11.0.20 select_tag(name, option_tags = nil, options = {})

Creates a drop-down selection box or, if the :multiple option is set to true, a multiple-choice selection box. The option_tags parameter is an actual string of option tags to put inside the select tag. You should not have to generate that string explicitly yourself. Instead, use the helpers in FormOptions (covered in the previous section of this chapter), which can be used to create common select boxes such as countries, time zones, or associated records.

11.11.0.21 submit_tag(value = "Save changes", options = {})

Creates a submit button with the text value as the caption. In conjunction with the unobtrusive JavaScript driver, one can set a :data attribute named :disable_with that can be used to provide a name for disabled versions of the submit button.

submit_tag('Save article', data: { disable_with: 'Please wait...' })
# => <input data-disable-with="Please wait..."
#      name="commit" type="submit" value="Save article" />

11.11.0.22 telephone_field_tag(name, value = nil, options = {})

Creates a telephone input field. This method is otherwise identical to text_field_tag and is aliased as phone_field_tag.

11.11.0.23 text_area_tag(name, content = nil, options = {})

Creates a multiline text input field (the textarea tag). The :size option lets you easily specify the dimensions of the text area instead of having to resort to explicit :rows and :cols options.

text_area_tag(:body, nil, size: "25x10")
# => <textarea name="body" id="body" cols="25" rows="10"></textarea>

11.11.0.24 text_field_tag(name, value = nil, options = {})

Creates a standard text input field.

11.11.0.25 time_field_tag(name, value = nil, options = {})

Creates an input field of type “time.” This method is otherwise identical to text_field_tag with the following additional options:

:min The minimum acceptable value.

:max The maximum acceptable value.

:step The acceptable value granularity.

11.11.0.26 url_field_tag(name, value = nil, options = {})

Creates an input field of type “url.” This method is otherwise identical to text_field_tag.

11.11.0.27 utf8_enforcer_tag()

Creates the hidden UTF-8 enforcer tag.

utf8_enforcer_tag
# => <input name="utf8" type="hidden" value="&#x2713;" />

11.11.0.28 week_field_tag(name, value = nil, options = {})

Creates an input field of type “week.” This method is otherwise identical to text_field_tag with the following additional options:

:min The minimum acceptable value.

:max The maximum acceptable value.

:step The acceptable value granularity.

11.12 JavaScriptHelper

Provides helper methods to facilitate inclusion of JavaScript code in your templates.

11.12.0.1 escape_javascript(javascript)

Escapes line breaks; single and double quotes are used for JavaScript segments. It’s also aliased as j.

11.12.0.2 javascript_tag(content_or_options_with_block = nil, html_options = {}, &block)

Outputs a script tag with the content inside. The html_options are added as tag attributes.

11.13 NumberHelper

This module provides assistance in converting numeric data to formatted strings suitable for displaying in your view. Methods are provided for phone numbers, currency, percentages, precision, positional notation, and file size.

11.13.0.1 number_to_currency(number, options = {})

Formats a number into a currency string. You can customize the format in the options hash.

:locale Sets the locale to be used for formatting. Defaults to current locale.

:precision Sets the level of precision. Defaults to 2.

:unit Sets the denomination of the currency. Defaults to "$".

:separator Sets the separator between the units. Defaults to ".".

:delimiter Sets the thousands delimiter. Defaults to ",".

:format Sets the format for nonnegative numbers. Defaults to "%u%n".

:negative_format Sets the format for negative numbers. Defaults to prepending a hyphen to the formatted number.

:raise Setting to true raises InvalidNumberError when the number is invalid.

 1 number_to_currency(1234567890.50)
 2 # => $1,234,567,890.50
 3
 4 number_to_currency(1234567890.506)
 5 # => $1,234,567,890.51
 6
 7 number_to_currency(1234567890.506, precision: 3)
 8 # => $1,234,567,890.506
 9
10 number_to_currency(1234567890.50, unit: "&pound;", separator: ",",
11   delimiter: "")
12 # => &pound;1234567890,50

11.13.0.2 number_to_human_size(number, options = {})

Formats a number that is more readable to humans. Useful for numbers that are extremely large. You can customize the format in the options hash.

:locale Sets the locale to be used for formatting. Defaults to current locale.

:precision Sets the level of precision. Defaults to 3.

:significant If true, precision will be the number of significant_digits; otherwise, the number of fractional digits are used. Defaults to true.

:separator Sets the separator between fractional and integer digits. Defaults to ".".

:delimiter Sets the thousands delimiter. Defaults to "".

:strip_insignificant_zeros Setting to true removes insignificant zeros after the decimal separator. Defaults to true.

:units A hash of unit quantifier names or a string containing an I18n scope indicating where to find this hash. It might have the following keys:

integers: :unit, :ten, *:hundred, :thousand, :million, *:billion, :trillion, *:quadrillion

fractionals: :deci, :centi, *:milli, :micro, :nano, *:pico, :femto

:format Sets the format for nonnegative numbers. Defaults to "%n %u". The field types are the following:

   %u: The quantifier
   %n: The number

1 number_to_human(123)                      # => "123"
2 number_to_human(1234)                     # => "1.23 Thousand"
3 number_to_human(1234567)                  # => "1.23 Million"
4 number_to_human(489939, precision: 4)     # => "489.9 Thousand"


Kevin Says ...

Rails provides the ability to set your own custom unit qualifier by setting the :units option.

1 number_to_human(10000, units: {unit: "m", thousand: "km"})  # => "10 km"


11.13.0.3 number_to_human_size(number, options = {})

Formats the bytes in size into a more understandable representation. Useful for reporting file sizes to users. You can customize the format in the options hash.

:locale Sets the locale to be used for formatting. Defaults to current locale.

:precision Sets the level of precision. Defaults to 3.

:significant If true, precision will be the number of significant_digits; otherwise, the number of fractional digits are used. Defaults to true.

:separator Sets the separator between fractional and integer digits. Defaults to ".".

:delimiter Sets the thousands delimiter. Defaults to "".

:strip_insignificant_zeros Setting to true removes insignificant zeros after the decimal separator. Defaults to true.

:format Sets the format for nonnegative numbers. Defaults to "%u%n".

:prefix Setting to :si formats the number using the SI prefix. Defaults to :binary.

:raise Setting to true raises InvalidNumberError when the number is invalid.

1 number_to_human_size(123)                   => 123 Bytes
2 number_to_human_size(1234)                  => 1.21 KB
3 number_to_human_size(12345)                 => 12.1 KB
4 number_to_human_size(1234567)               => 1.18 MB
5 number_to_human_size(1234567890)            => 1.15 GB
6 number_to_human_size(1234567890123)         => 1.12 TB
7 number_to_human_size(1234567, precision: 2) => 1.2 MB

11.13.0.4 number_to_percentage(number, options = {})

Formats a number as a percentage string. You can customize the format in the options hash.

:locale Sets the locale to be used for formatting. Defaults to current locale.

:precision Sets the level of precision. Defaults to 3.

:significant If true, precision will be the number of significant_digits; otherwise, the number of fractional digits are used. Defaults to false.

:separator Sets the separator between the units. Defaults to "."

:delimiter Sets the thousands delimiter. Defaults to "".

:strip_insignificant_zeros Setting to true removes insignificant zeros after the decimal separator. Defaults to false.

:format Sets the format of the percentage string. Defaults to "%n%".

:raise Setting to true raises InvalidNumberError when the number is invalid.

1 number_to_percentage(100)                      => 100.000%
2 number_to_percentage(100, precision: 0)        => 100%
3 number_to_percentage(302.0574, precision: 2)   => 302.06%

11.13.0.5 number_to_phone(number, options = {})

Formats a number as a US phone number. You can customize the format in the options hash.

:area_code Adds parentheses around the area code.

:delimiter Specifies the delimiter to use. Defaults to "-".

:extension Specifies an extension to add to the end of the generated number.

:country_code Sets the country code for the phone number.

:raise Setting to true raises InvalidNumberError when the number is invalid.

1 number_to_phone(1235551234)                     # => "123-555-1234"
2 number_to_phone(1235551234, area_code: true)    # => "(123) 555-1234"
3 number_to_phone(1235551234, delimiter: " ")     # => "123 555 1234"

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.183.210