diff options
Diffstat (limited to 'railties')
-rw-r--r-- | railties/Rakefile | 4 | ||||
-rw-r--r-- | railties/doc/guides/html/active_record_basics.html | 402 | ||||
-rw-r--r-- | railties/doc/guides/html/form_helpers.html | 296 | ||||
-rw-r--r-- | railties/doc/guides/html/i18n.html | 317 | ||||
-rw-r--r-- | railties/doc/guides/source/form_helpers.txt | 261 | ||||
-rw-r--r-- | railties/doc/guides/source/i18n.txt | 181 |
6 files changed, 1140 insertions, 321 deletions
diff --git a/railties/Rakefile b/railties/Rakefile index be0f449efc..30d3748441 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -285,7 +285,7 @@ task :guides do asciidoc_conf = 'doc/guides/asciidoc.conf' ignore = ['..', 'icons', 'images', 'templates', 'stylesheets'] - ignore << 'active_record_basics.txt' + #ignore << 'active_record_basics.txt' indexless = ['index.txt', 'authors.txt'] @@ -301,7 +301,7 @@ task :guides do end entries.each do |entry| - next if ignore.include?(entry) + next if ignore.include?(entry) or entry =~ /^\./ # because Vim is always saving hidden swap files if File.directory?(File.join(source, entry)) # If the current entry is a directory, then we will want to compile diff --git a/railties/doc/guides/html/active_record_basics.html b/railties/doc/guides/html/active_record_basics.html new file mode 100644 index 0000000000..04f1e3e838 --- /dev/null +++ b/railties/doc/guides/html/active_record_basics.html @@ -0,0 +1,402 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <title>Active Record Basics</title> + <!--[if lt IE 8]> + <script src="http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE8.js" type="text/javascript"></script> + <![endif]--> + <link href="stylesheets/base.css" media="screen" rel="Stylesheet" type="text/css" /> + <link href="stylesheets/forms.css" media="screen" rel="Stylesheet" type="text/css" /> + <link href="stylesheets/more.css" media="screen" rel="Stylesheet" type="text/css" /> +</head> +<body> + <div id="header" > + <div id="logo"> + <a href="index.html" title="Ruby on Rails"><img src="images/rails_logo_remix.gif" alt="Rails" height="140" width="110" /></a> + </div> + + <h1 id="site_title"><span>Ruby on Rails</span></h1> + <h2 id="site_title_tagline">Sustainable productivity for web-application development</h2> + + <ul id="navMain"> + <li class="first-child"><a href="http://www.rubyonrails.org/" title="Ruby on Rails" class="ruby_on_rails">Ruby on Rails</a></li> + <li><a class="manuals" href="index.html" title="Manuals Index">Guides Index</a></li> + </ul> + </div> + + <div id="container"> + + <div id="sidebar"> + <h2>Chapters</h2> + <ol> + <li> + <a href="#_orm_the_blueprint_of_active_record">ORM The Blueprint of Active Record</a> + </li> + <li> + <a href="#_active_record_the_engine_of_rails">Active Record The Engine of Rails</a> + <ul> + + <li><a href="#_rails_active_record_conventions">Rails Active Record Conventions</a></li> + + </ul> + </li> + <li> + <a href="#_philosophical_approaches_amp_common_conventions">Philosophical Approaches & Common Conventions</a> + </li> + <li> + <a href="#_activerecord_magic">ActiveRecord Magic</a> + </li> + <li> + <a href="#_how_activerecord_maps_your_database">How ActiveRecord Maps your Database.</a> + </li> + <li> + <a href="#_growing_your_database_relationships_naturally">Growing Your Database Relationships Naturally</a> + </li> + <li> + <a href="#_attributes">Attributes</a> + </li> + <li> + <a href="#_validations_amp_callbacks">Validations & Callbacks</a> + </li> + </ol> + </div> + + <div id="content"> + <h1>Active Record Basics</h1> + <div id="preamble">
+<div class="sectionbody">
+<div class="paragraph"><p>Active Record is a design pattern that mitigates the mind-numbing mental gymnastics often needed to get your application to communicate with a database. This guide uses a mix of real-world examples, metaphors and detailed explanations of the actual Rails source code to help you make the most of ActiveRecord.</p></div>
+<div class="paragraph"><p>After reading this guide readers should have a strong grasp of the Active Record pattern and how it can be used with or without Rails. Hopefully, some of the philosophical and theoretical intentions discussed here will also make them a stronger and better developer.</p></div>
+</div>
+</div>
+<h2 id="_orm_the_blueprint_of_active_record">1. ORM The Blueprint of Active Record</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If Active Record is the engine of Rails then ORM is the blueprint of that engine. ORM is short for “Object Relational Mapping” and is a programming concept used to make structures within a system relational. As a thought experiment imagine the components that make up a typical car. There are doors, seats, windows, engines etc. Viewed independently they are simple parts, yet when bolted together through the aid of a blueprint, the parts become a more complex device. ORM is the blueprint that describes how the individual parts relate to one another and in some cases infers the part’s purpose through the way the associations are described.</p></div>
+</div>
+<h2 id="_active_record_the_engine_of_rails">2. Active Record The Engine of Rails</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Active Record is a design pattern used to access data within a database. The name “Active Record” was coined by Martin Fowler in his book “Patterns of Enterprise Application Architecture”. Essentially, when a record is returned from the database instead of being just the data it is wrapped in a class, which gives you methods to control that data with. The rails framework is built around the MVC (Model View Controller) design patten and the Active Record is used as the default Model.</p></div>
+<div class="paragraph"><p>The Rails community added several useful concepts to their version of Active Record, including inheritance and associations, which are extremely useful for web applications. The associations are created by using a DSL (domain specific language) of macros, and inheritance is achieved through the use of STI (Single Table Inheritance) at the database level.</p></div>
+<div class="paragraph"><p>By following a few simple conventions the Rails Active Record will automatically map between:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Classes & Database Tables
+</p>
+</li>
+<li>
+<p>
+Class attributes & Database Table Columns
+</p>
+</li>
+</ul></div>
+<h3 id="_rails_active_record_conventions">2.1. Rails Active Record Conventions</h3>
+<div class="paragraph"><p>Here are the key conventions to consider when using Active Record.</p></div>
+<h4 id="_naming_conventions">2.1.1. Naming Conventions</h4>
+<div class="paragraph"><p>Database Table - Plural with underscores separating words i.e. (book_clubs)
+Model Class - Singular with the first letter of each word capitalized i.e. (BookClub)
+Here are some additional Examples:</p></div>
+<div class="tableblock">
+<table rules="all"
+frame="hsides"
+cellspacing="0" cellpadding="4">
+<col width="160" />
+<col width="182" />
+<thead>
+ <tr>
+ <th align="left">
+ Model / Class
+ </th>
+ <th align="left">
+ Table / Schema
+ </th>
+ </tr>
+</thead>
+<tbody valign="top">
+ <tr>
+ <td align="left">
+ Post
+ </td>
+ <td align="left">
+ posts
+ </td>
+ </tr>
+ <tr>
+ <td align="left">
+ LineItem
+ </td>
+ <td align="left">
+ line_items
+ </td>
+ </tr>
+ <tr>
+ <td align="left">
+ Deer
+ </td>
+ <td align="left">
+ deer
+ </td>
+ </tr>
+ <tr>
+ <td align="left">
+ Mouse
+ </td>
+ <td align="left">
+ mice
+ </td>
+ </tr>
+ <tr>
+ <td align="left">
+ Person
+ </td>
+ <td align="left">
+ people
+ </td>
+ </tr>
+</tbody>
+</table>
+</div>
+<h4 id="_schema_conventions">2.1.2. Schema Conventions</h4>
+<div class="paragraph"><p>To take advantage of some of the magic of Rails database tables must be modeled
+to reflect the ORM decisions that Rails makes.</p></div>
+<div class="tableblock">
+<table rules="all"
+frame="hsides"
+cellspacing="0" cellpadding="4">
+<col width="160" />
+<col width="937" />
+<thead>
+ <tr>
+ <th align="left">
+ Convention
+ </th>
+ <th align="left">
+ </th>
+ </tr>
+</thead>
+<tbody valign="top">
+ <tr>
+ <td align="left">
+ Foreign keys
+ </td>
+ <td align="left">
+ These fields are named table_id i.e. (item_id, order_id)
+ </td>
+ </tr>
+ <tr>
+ <td align="left">
+ Primary Key
+ </td>
+ <td align="left">
+ Rails automatically creates a primary key column named "id" unless told otherwise.
+ </td>
+ </tr>
+</tbody>
+</table>
+</div>
+<h4 id="_magic_field_names">2.1.3. Magic Field Names</h4>
+<div class="paragraph"><p>When these optional fields are used in your database table definition they give the Active Record
+instance additional features.</p></div>
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<img src="./images/icons/note.png" alt="Note" />
+</td>
+<td class="content">While these column names are optional they are in fact reserved by ActiveRecord. Steer clear of reserved keywords unless you want the extra functionality. For example, "type" is a reserved keyword
+used to designate a table using Single Table Inheritance. If you are not using STI, try an analogous
+keyword like "context", that may still accurately describe the data you are modeling.</td>
+</tr></table>
+</div>
+<div class="tableblock">
+<table rules="all"
+frame="hsides"
+cellspacing="0" cellpadding="4">
+<col width="285" />
+<col width="902" />
+<thead>
+ <tr>
+ <th align="left">
+ Attribute
+ </th>
+ <th align="left">
+ Purpose
+ </th>
+ </tr>
+</thead>
+<tbody valign="top">
+ <tr>
+ <td align="left">
+ created_at / created_on
+ </td>
+ <td align="left">
+ Rails stores the current date & time to this field when creating the record.
+ </td>
+ </tr>
+ <tr>
+ <td align="left">
+ updated_at / updated_on
+ </td>
+ <td align="left">
+ Rails stores the current date & time to this field when updating the record.
+ </td>
+ </tr>
+ <tr>
+ <td align="left">
+ lock_version
+ </td>
+ <td align="left">
+ Adds optimistic locking to a model <a href="http://api.rubyonrails.com/classes/ActiveRecord/Locking.html">more about optimistic locking</a>.
+ </td>
+ </tr>
+ <tr>
+ <td align="left">
+ type
+ </td>
+ <td align="left">
+ Specifies that the model uses Single Table Inheritance <a href="http://api.rubyonrails.com/classes/ActiveRecord/Base.html">more about STI</a>.
+ </td>
+ </tr>
+ <tr>
+ <td align="left">
+ id
+ </td>
+ <td align="left">
+ All models require an id. the default is name is "id" but can be changed using the "set_primary_key" or "primary_key" methods.
+ </td>
+ </tr>
+ <tr>
+ <td align="left">
+ <em>table_name</em>\_count
+ </td>
+ <td align="left">
+ Can be used to caches the number of belonging objects on the associated class.
+ </td>
+ </tr>
+</tbody>
+</table>
+</div>
+<div class="paragraph"><p>By default rails assumes all tables will use “id” as their primary key to identify each record. Though fortunately you won’t have explicitly declare this, Rails will automatically create that field unless you tell it not to.</p></div>
+<div class="paragraph"><p>For example suppose you created a database table called cars:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt>mysql<span style="color: #990000">></span> <span style="font-weight: bold"><span style="color: #0000FF">CREATE</span></span> <span style="font-weight: bold"><span style="color: #0000FF">TABLE</span></span> cars <span style="color: #990000">(</span>
+ id <span style="color: #009900">INT</span><span style="color: #990000">,</span>
+ color <span style="color: #009900">VARCHAR</span><span style="color: #990000">(</span><span style="color: #993399">100</span><span style="color: #990000">),</span>
+ doors <span style="color: #009900">INT</span><span style="color: #990000">,</span>
+ horses <span style="color: #009900">INT</span><span style="color: #990000">,</span>
+ model <span style="color: #009900">VARCHAR</span><span style="color: #990000">(</span><span style="color: #993399">100</span><span style="color: #990000">)</span>
+ <span style="color: #990000">);</span></tt></pre></div></div>
+<div class="paragraph"><p>Now you created a class named Car, which is to represent an instance of a record from your table.</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Car
+<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
+<div class="paragraph"><p>As you might expect without defining the explicit mappings between your class and the table it is impossible for Rails or any other program to correctly map those relationships.</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="color: #990000">>></span> c <span style="color: #990000">=</span> Car<span style="color: #990000">.</span>new
+<span style="color: #990000">=></span> <span style="font-style: italic"><span style="color: #9A1900">#<Class:0x11e1e90></span></span>
+<span style="color: #990000">>></span> c<span style="color: #990000">.</span>doors
+NoMethodError<span style="color: #990000">:</span> undefined method `doors' <span style="font-weight: bold"><span style="color: #0000FF">for</span></span> <span style="font-style: italic"><span style="color: #9A1900">#<Class:0x11e1e90></span></span>
+ from <span style="color: #990000">(</span>irb<span style="color: #990000">):</span><span style="color: #993399">2</span></tt></pre></div></div>
+<div class="paragraph"><p>Now you could define a door methods to write and read data to and from the database. In a nutshell this is what ActiveRecord does. According to the Rails API:
+“Active Record objects don‘t specify their attributes directly, but rather infer them from the table definition with which they‘re linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.”
+Lets try our Car class again, this time inheriting from ActiveRecord.</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Car <span style="color: #990000"><</span> ActiveRecord<span style="color: #990000">::</span>Base
+<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
+<div class="paragraph"><p>Now if we try to access an attribute of the table ActiveRecord automatically handles the mappings for us, as you can see in the following example.</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="color: #990000">>></span> c <span style="color: #990000">=</span> Car<span style="color: #990000">.</span>new
+<span style="color: #990000">=></span> <span style="font-style: italic"><span style="color: #9A1900">#<Car id: nil, doors: nil, color: nil, horses: nil, model: nil></span></span>
+<span style="color: #990000">>></span> c<span style="color: #990000">.</span>doors
+<span style="color: #990000">=></span> <span style="font-weight: bold"><span style="color: #0000FF">nil</span></span></tt></pre></div></div>
+<div class="paragraph"><p>Rails further extends this model by giving each ActiveRecord a way of describing the variety of ways records are associated with one another. We will touch on some of these associations later in the guide but I encourage readers who are interested to read the guide to ActiveRecord associations for an in-depth explanation of the variety of ways rails can model associations.
+- Associations between objects controlled by meta-programming macros.</p></div>
+</div>
+<h2 id="_philosophical_approaches_amp_common_conventions">3. Philosophical Approaches & Common Conventions</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Rails has a reputation of being a zero-config framework which means that it aims to get you off the ground with as little pre-flight checking as possible. This speed benefit is achieved by following “Convention over Configuration”, which is to say that if you agree to live with the defaults then you benefit from a the inherent speed-boost. As Courtneay Gasking put it to me once “You don’t want to off-road on Rails”. ActiveRecord is no different, while it’s possible to override or subvert any of the conventions of AR, unless you have a good reason for doing so you will probably be happy with the defaults. The following is a list of the common conventions of ActiveRecord</p></div>
+</div>
+<h2 id="_activerecord_magic">4. ActiveRecord Magic</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+timestamps
+</p>
+</li>
+<li>
+<p>
+updates
+</p>
+</li>
+</ul></div>
+</div>
+<h2 id="_how_activerecord_maps_your_database">5. How ActiveRecord Maps your Database.</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+sensible defaults
+</p>
+</li>
+<li>
+<p>
+overriding conventions
+</p>
+</li>
+</ul></div>
+</div>
+<h2 id="_growing_your_database_relationships_naturally">6. Growing Your Database Relationships Naturally</h2>
+<div class="sectionbody">
+</div>
+<h2 id="_attributes">7. Attributes</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+attribute accessor method. How to override them?
+</p>
+</li>
+<li>
+<p>
+attribute?
+</p>
+</li>
+<li>
+<p>
+dirty records
+ -
+== ActiveRecord handling the CRUD of your Rails application - Understanding the life-cycle of an ActiveRecord
+</p>
+</li>
+</ul></div>
+</div>
+<h2 id="_validations_amp_callbacks">8. Validations & Callbacks</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>see the Validations & Callbacks guide for more info.</p></div>
+</div>
+ + </div> + </div> +</body> +</html> diff --git a/railties/doc/guides/html/form_helpers.html b/railties/doc/guides/html/form_helpers.html index a43cbe584f..54155cddb6 100644 --- a/railties/doc/guides/html/form_helpers.html +++ b/railties/doc/guides/html/form_helpers.html @@ -31,35 +31,29 @@ <h2>Chapters</h2> <ol> <li> - <a href="#_basic_forms">Basic forms</a> + <a href="#_dealing_with_basic_forms">Dealing With Basic Forms</a> <ul> <li><a href="#_generic_search_form">Generic search form</a></li> <li><a href="#_multiple_hashes_in_form_helper_attributes">Multiple hashes in form helper attributes</a></li> - <li><a href="#_checkboxes_radio_buttons_and_other_controls">Checkboxes, radio buttons and other controls</a></li> - - <li><a href="#_how_do_forms_with_put_or_delete_methods_work">How do forms with PUT or DELETE methods work?</a></li> + <li><a href="#_helpers_for_generating_form_elements">Helpers for generating form elements</a></li> </ul> </li> <li> - <a href="#_different_families_of_helpers">Different Families of helpers</a> + <a href="#_dealing_with_model_objects">Dealing With Model Objects</a> <ul> - <li><a href="#_barebones_helpers">Barebones helpers</a></li> - <li><a href="#_model_object_helpers">Model object helpers</a></li> - </ul> - </li> - <li> - <a href="#_forms_that_deal_with_model_attributes">Forms that deal with model attributes</a> - <ul> + <li><a href="#_binding_a_form_to_an_object">Binding a form to an object</a></li> <li><a href="#_relying_on_record_identification">Relying on record identification</a></li> + <li><a href="#_how_do_forms_with_put_or_delete_methods_work">How do forms with PUT or DELETE methods work?</a></li> + </ul> </li> <li> @@ -77,10 +71,10 @@ </ul> </li> <li> - <a href="#_date_and_time_select_boxes">Date and time select boxes</a> + <a href="#_using_date_and_time_form_helpers">Using Date and Time Form Helpers</a> <ul> - <li><a href="#_barebones_helpers_2">Barebones helpers</a></li> + <li><a href="#_barebones_helpers">Barebones helpers</a></li> <li><a href="#_model_object_helpers_2">Model object helpers</a></li> @@ -89,15 +83,7 @@ </ul> </li> <li> - <a href="#_form_builders">Form builders</a> - <ul> - - <li><a href="#_scoping_out_form_controls_with_tt_fields_for_tt">Scoping out form controls with <tt>fields_for</tt></a></li> - - </ul> - </li> - <li> - <a href="#_file_uploads">File Uploads</a> + <a href="#_uploading_files">Uploading Files</a> <ul> <li><a href="#_what_gets_uploaded">What gets uploaded</a></li> @@ -107,7 +93,10 @@ </ul> </li> <li> - <a href="#_parameter_names">Parameter Names</a> + <a href="#_customising_form_builders">Customising Form Builders</a> + </li> + <li> + <a href="#_understanding_parameter_naming_conventions">Understanding Parameter Naming Conventions</a> <ul> <li><a href="#_basic_structures">Basic structures</a></li> @@ -119,7 +108,7 @@ </ul> </li> <li> - <a href="#_complex_forms">Complex forms</a> + <a href="#_building_complex_forms">Building Complex forms</a> </li> <li> <a href="#_changelog">Changelog</a> @@ -165,7 +154,7 @@ Learn what makes a file upload form different; </div>
</div>
</div>
-<h2 id="_basic_forms">1. Basic forms</h2>
+<h2 id="_dealing_with_basic_forms">1. Dealing With Basic Forms</h2>
<div class="sectionbody">
<div class="paragraph"><p>The most basic form helper is <tt>form_tag</tt>.</p></div>
<div class="listingblock">
@@ -294,7 +283,19 @@ a submit element. <td class="content">Do not delimit the second hash without doing so with the first hash, otherwise your method invocation will result in an <tt>expecting tASSOC</tt> syntax error.</td>
</tr></table>
</div>
-<h3 id="_checkboxes_radio_buttons_and_other_controls">1.3. Checkboxes, radio buttons and other controls</h3>
+<h3 id="_helpers_for_generating_form_elements">1.3. Helpers for generating form elements</h3>
+<div class="paragraph"><p>Rails provides a series of helpers for generating form elements such as checkboxes, text fields, radio buttons and so. These basic helpers, with names ending in _tag such as <tt>text_field_tag</tt>, <tt>check_box_tag</tt> just generate a single <tt><input></tt> element. The first parameter to these is always the name of the input. This is the name under which value will appear in the <tt>params</tt> hash in the controller. For example if the form contains</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt><%= text_field_tag(:query) %></tt></pre>
+</div></div>
+<div class="paragraph"><p>then the controller code should use</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt>params[:query]</tt></pre>
+</div></div>
+<div class="paragraph"><p>to retrieve the value entered by the user. When naming inputs be aware that Rails uses certain conventions that control whether values appear at the top level of the params hash, inside an array or a nested hash and so on. You can read more about them in the <a href="#parameter_names">parameter names</a> section. For details on the precise usage of these helpers, please refer to the <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html">API documentation</a>.</p></div>
+<h4 id="_checkboxes">1.3.1. Checkboxes</h4>
<div class="paragraph"><p>Checkboxes are form controls that give the user a set of options they can enable or disable:</p></div>
<div class="listingblock">
<div class="content">
@@ -310,6 +311,8 @@ output: <input id="pet_cat" name="pet_cat" type="checkbox" value="1" />
<label for="pet_cat">I own a cat</label></tt></pre>
</div></div>
+<div class="paragraph"><p>The second parameter to <tt>check_box_tag</tt> is the value of the input. This is the value that will be submitted by the browser if the checkbox is ticked (i.e. the value that will be present in the params hash). With the above form you would check the value of <tt>params[:pet_dog]</tt> and <tt>params[:pet_cat]</tt> to see which pets the user owns.</p></div>
+<h4 id="_radio_buttons">1.3.2. Radio buttons</h4>
<div class="paragraph"><p>Radio buttons, while similar to checkboxes, are controls that specify a set of options in which they are mutually exclusive (user can only pick one):</p></div>
<div class="listingblock">
<div class="content">
@@ -325,6 +328,7 @@ output: <input id="age_adult" name="age" type="radio" value="adult" />
<label for="age_adult">I'm over 21</label></tt></pre>
</div></div>
+<div class="paragraph"><p>As with <tt>check_box_tag</tt> the second parameter to <tt>radio_button_tag</tt> is the value of the input. Because these two radio buttons share the same name (age) the user will only be able to select one and <tt>params[:age]</tt> will contain either <tt>child</tt> or <tt>adult</tt>.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
@@ -333,7 +337,8 @@ output: <td class="content">Always use labels for each checkbox and radio button. They associate text with a specific option and provide a larger clickable region.</td>
</tr></table>
</div>
-<div class="paragraph"><p>Other form controls worth mentioning are the text area, password input and hidden input:</p></div>
+<h4 id="_other_helpers_of_interest">1.3.3. Other helpers of interest</h4>
+<div class="paragraph"><p>Other form controls worth mentioning are the text area, password input and hidden input:</p></div>
<div class="listingblock">
<div class="content">
<pre><tt><%= text_area_tag(:message, "Hi, nice site", :size => "24x6") %>
@@ -346,7 +351,7 @@ output: <input id="password" name="password" type="password" />
<input id="parent_id" name="parent_id" type="hidden" value="5" /></tt></pre>
</div></div>
-<div class="paragraph"><p>Hidden inputs are not shown to the user, but they hold data same as any textual input. Values inside them can be changed with JavaScript.</p></div>
+<div class="paragraph"><p>Hidden inputs are not shown to the user, but they hold data like any textual input. Values inside them can be changed with JavaScript.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
@@ -355,42 +360,12 @@ output: <td class="content">If you’re using password input fields (for any purpose), you might want to prevent their values showing up in application logs by activating <tt>filter_parameter_logging(:password)</tt> in your ApplicationController.</td>
</tr></table>
</div>
-<h3 id="_how_do_forms_with_put_or_delete_methods_work">1.4. How do forms with PUT or DELETE methods work?</h3>
-<div class="paragraph"><p>Rails framework encourages RESTful design of your applications, which means you’ll be making a lot of "PUT" and "DELETE" requests (besides "GET" and "POST"). Still, most browsers <em>don’t support</em> methods other than "GET" and "POST" when it comes to submitting forms. How does this work, then?</p></div>
-<div class="paragraph"><p>Rails works around this issue by emulating other methods over POST with a hidden input named <tt>"_method"</tt> that is set to reflect the desired method:</p></div>
-<div class="listingblock">
-<div class="content">
-<pre><tt>form_tag(search_path, :method => "put")
-
-output:
-
-<form action="/search" method="post">
- <div style="margin:0;padding:0">
- <input name="_method" type="hidden" value="put" />
- <input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
- </div>
- ...</tt></pre>
-</div></div>
-<div class="paragraph"><p>When parsing POSTed data, Rails will take into account the special <tt>_method</tt> parameter and act as if the HTTP method was the one specified inside it ("PUT" in this example).</p></div>
</div>
-<h2 id="_different_families_of_helpers">2. Different Families of helpers</h2>
+<h2 id="_dealing_with_model_objects">2. Dealing With Model Objects</h2>
<div class="sectionbody">
-<div class="paragraph"><p>Most of Rails' form helpers are available in two forms.</p></div>
-<h3 id="_barebones_helpers">2.1. Barebones helpers</h3>
-<div class="paragraph"><p>These just generate the appropriate markup. These have names ending in _tag such as <tt>text_field_tag</tt>, <tt>check_box_tag</tt>. The first parameter to these is always the name of the input. This is the name under which value will appear in the <tt>params</tt> hash in the controller. For example if the form contains</p></div>
-<div class="listingblock">
-<div class="content">
-<pre><tt><%= text_field_tag(:query) %></tt></pre>
-</div></div>
-<div class="paragraph"><p>then the controller code should use</p></div>
-<div class="listingblock">
-<div class="content">
-<pre><tt>params[:query]</tt></pre>
-</div></div>
-<div class="paragraph"><p>to retrieve the value entered by the user. When naming inputs be aware that Rails uses certain conventions that control whether values appear at the top level of the params hash, inside an array or a nested hash and so on. You can read more about them in the <a href="#parameter_names">parameter names</a> section. For details on the precise usage of these helpers, please refer to the <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html">API documentation</a>.</p></div>
-<h3 id="_model_object_helpers">2.2. Model object helpers</h3>
-<div class="paragraph"><p>These are designed to work with a model object (commonly an Active Record object but this need not be the case). These lack the _tag suffix, for example <tt>text_field</tt>, <tt>text_area</tt>.</p></div>
-<div class="paragraph"><p>For these helpers the first arguement is the name of an instance variable and the second is the name a method (usually an attribute) to call on that object. Rails will set the value of the input control to the return value of that method for the object and set an appropriate input name. If your controller has defined <tt>@person</tt> and that person’s name is Henry then a form containing:</p></div>
+<h3 id="_model_object_helpers">2.1. Model object helpers</h3>
+<div class="paragraph"><p>A particularly common task for a form is editing or creating a model object. While the <tt>*_tag</tt> helpers could certainly be used for this task they are somewhat verbose as for each tag you would have to ensure the correct parameter name is used and set the default value of the input appropriately. Rails provides helpers tailored to this task. These helpers lack the _tag suffix, for example <tt>text_field</tt>, <tt>text_area</tt>.</p></div>
+<div class="paragraph"><p>For these helpers the first argument is the name of an instance variable and the second is the name of a method (usually an attribute) to call on that object. Rails will set the value of the input control to the return value of that method for the object and set an appropriate input name. If your controller has defined <tt>@person</tt> and that person’s name is Henry then a form containing:</p></div>
<div class="listingblock">
<div class="content">
<pre><tt><%= text_field(:person, :name) %></tt></pre>
@@ -411,10 +386,10 @@ output: </td>
</tr></table>
</div>
-</div>
-<h2 id="_forms_that_deal_with_model_attributes">3. Forms that deal with model attributes</h2>
-<div class="sectionbody">
-<div class="paragraph"><p>While the helpers seen so far are handy Rails can save you some work. For example typically a form is used to edit multiple attributes of a single object, so having to repeat the name of the object being edited is clumsy. The following examples will handle an Article model. First, have the controller create one:</p></div>
+<div class="paragraph"><p>Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the <a href="./activerecord_validations_callbacks.html#_using_the_tt_errors_tt_collection_in_your_view_templates">Active Record Validations and Callbacks</a> guide.</p></div>
+<h3 id="_binding_a_form_to_an_object">2.2. Binding a form to an object</h3>
+<div class="paragraph"><p>While this is an increase in comfort it is far from perfect. If Person has many attributes to edit then we would be repeating the name of the edited object many times. What we want to do is somehow bind a form to a model object which is exactly what <tt>form_for</tt> does.</p></div>
+<div class="paragraph"><p>Assume we have a controller for dealing with articles:</p></div>
<div class="listingblock">
<div class="title">articles_controller.rb</div>
<div class="content">
@@ -422,7 +397,7 @@ output: @article = Article.new
end</tt></pre>
</div></div>
-<div class="paragraph"><p>Now switch to the view. The first thing to remember is to use the <tt>form_for</tt> helper instead of <tt>form_tag</tt>, and that you should pass the model name and object as arguments:</p></div>
+<div class="paragraph"><p>The corresponding view using <tt>form_for</tt> looks like this</p></div>
<div class="listingblock">
<div class="title">articles/new.html.erb</div>
<div class="content">
@@ -436,7 +411,7 @@ end</tt></pre> <div class="olist arabic"><ol class="arabic">
<li>
<p>
-<tt>:article</tt> is the name of the model and <tt>@article</tt> is the record.
+<tt>:article</tt> is the name of the model and <tt>@article</tt> is the actual object being edited.
</p>
</li>
<li>
@@ -446,7 +421,7 @@ There is a single hash of options. Routing options are passed inside <tt>:url</t </li>
<li>
<p>
-The <tt>form_for</tt> method yields <strong>a form builder</strong> object (the <tt>f</tt> variable).
+The <tt>form_for</tt> method yields a <strong>form builder</strong> object (the <tt>f</tt> variable).
</p>
</li>
<li>
@@ -466,8 +441,27 @@ Methods to create form controls are called <strong>on</strong> the form builder </div></div>
<div class="paragraph"><p>The name passed to <tt>form_for</tt> controls where in the params hash the form values will appear. Here the name is <tt>article</tt> and so all the inputs have names of the form <tt>article[attribute_name]</tt>. Accordingly, in the <tt>create</tt> action <tt>params[:article]</tt> will be a hash with keys <tt>:title</tt> and <tt>:body</tt>. You can read more about the significance of input names in the <a href="#parameter_names">parameter names</a> section.</p></div>
<div class="paragraph"><p>The helper methods called on the form builder are identical to the model object helpers except that it is not necessary to specify which object is being edited since this is already managed by the form builder.</p></div>
-<h3 id="_relying_on_record_identification">3.1. Relying on record identification</h3>
-<div class="paragraph"><p>In the previous chapter you handled the Article model. This model is directly available to users of our application, so — following the best practices for developing with Rails — you should declare it <strong>a resource</strong>.</p></div>
+<div class="paragraph"><p>You can create a similar binding without actually creating <tt><form></tt> tags with the <tt>fields_for</tt> helper. This is useful for editing additional model objects with the same form. For example if you had a Person model with an associated ContactDetail model you could create a form for editing both like so:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt><% form_for @person do |person_form| %>
+ <%= person_form.text_field :name %>
+ <% fields_for @person.contact_detail do |contact_details_form| %>
+ <%= contact_details_form.text_field :phone_number %>
+ <% end %>
+<% end %></tt></pre>
+</div></div>
+<div class="paragraph"><p>which produces the following output:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt><form action="/people/1" class="edit_person" id="edit_person_1" method="post">
+ <input id="person_name" name="person[name]" size="30" type="text" />
+ <input id="contact_detail_phone_number" name="contact_detail[phone_number]" size="30" type="text" />
+</form></tt></pre>
+</div></div>
+<div class="paragraph"><p>The object yielded by <tt>fields_for</tt> is a form builder like the one yielded by <tt>form_for</tt> (in fact <tt>form_for</tt> calls <tt>fields_for</tt> internally).</p></div>
+<h3 id="_relying_on_record_identification">2.3. Relying on record identification</h3>
+<div class="paragraph"><p>The Article model is directly available to users of our application, so — following the best practices for developing with Rails — you should declare it <strong>a resource</strong>.</p></div>
<div class="paragraph"><p>When dealing with RESTful resources, calls to <tt>form_for</tt> can get significantly easier if you rely on <strong>record identification</strong>. In short, you can just pass the model instance and have Rails figure out model name and the rest:</p></div>
<div class="listingblock">
<div class="content">
@@ -493,7 +487,7 @@ form_for(@article)</tt></pre> <td class="content">When you’re using STI (single-table inheritance) with your models, you can’t rely on record identification on a subclass if only their parent class is declared a resource. You will have to specify the model name, <tt>:url</tt> and <tt>:method</tt> explicitly.</td>
</tr></table>
</div>
-<h4 id="_dealing_with_namespaces">3.1.1. Dealing with namespaces</h4>
+<h4 id="_dealing_with_namespaces">2.3.1. Dealing with namespaces</h4>
<div class="paragraph"><p>If you have created namespaced routes <tt>form_for</tt> has a nifty shorthand for that too. If your application has an admin namespace then</p></div>
<div class="listingblock">
<div class="content">
@@ -504,12 +498,29 @@ form_for(@article)</tt></pre> <div class="content">
<pre><tt>form_for [:admin, :management, @article]</tt></pre>
</div></div>
-<div class="paragraph"><p>For more information on Rails' routing system and the associated conventions, please see the <a href="../routing_outside_in.html">routing guide</a>.</p></div>
+<div class="paragraph"><p>For more information on Rails' routing system and the associated conventions, please see the <a href="./routing_outside_in.html">routing guide</a>.</p></div>
+<h3 id="_how_do_forms_with_put_or_delete_methods_work">2.4. How do forms with PUT or DELETE methods work?</h3>
+<div class="paragraph"><p>Rails framework encourages RESTful design of your applications, which means you’ll be making a lot of "PUT" and "DELETE" requests (besides "GET" and "POST"). Still, most browsers <em>don’t support</em> methods other than "GET" and "POST" when it comes to submitting forms. How does this work, then?</p></div>
+<div class="paragraph"><p>Rails works around this issue by emulating other methods over POST with a hidden input named <tt>"_method"</tt> that is set to reflect the desired method:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt>form_tag(search_path, :method => "put")
+
+output:
+
+<form action="/search" method="post">
+ <div style="margin:0;padding:0">
+ <input name="_method" type="hidden" value="put" />
+ <input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" />
+ </div>
+ ...</tt></pre>
+</div></div>
+<div class="paragraph"><p>When parsing POSTed data, Rails will take into account the special <tt>_method</tt> parameter and act as if the HTTP method was the one specified inside it ("PUT" in this example).</p></div>
</div>
-<h2 id="_making_select_boxes_with_ease">4. Making select boxes with ease</h2>
+<h2 id="_making_select_boxes_with_ease">3. Making select boxes with ease</h2>
<div class="sectionbody">
-<div class="paragraph"><p>Select boxes in HTML require a significant amount of markup (one <tt>OPTION</tt> element for each option to choose from), therefore it makes the most sense for them to be dynamically generated from data stored in arrays or hashes.</p></div>
-<div class="paragraph"><p>Here is what our wanted markup might look like:</p></div>
+<div class="paragraph"><p>Select boxes in HTML require a significant amount of markup (one <tt>OPTION</tt> element for each option to choose from), therefore it makes the most sense for them to be dynamically generated.</p></div>
+<div class="paragraph"><p>Here is what the markup might look like:</p></div>
<div class="listingblock">
<div class="content">
<pre><tt><select name="city_id" id="city_id">
@@ -519,8 +530,8 @@ form_for(@article)</tt></pre> <option value="12">Berlin</option>
</select></tt></pre>
</div></div>
-<div class="paragraph"><p>Here you have a list of cities where their names are presented to the user, but internally the application only wants to handle their IDs so they are used as the options' value attributes. Let’s see how Rails can help out here.</p></div>
-<h3 id="_the_select_tag_and_options">4.1. The select tag and options</h3>
+<div class="paragraph"><p>Here you have a list of cities whose names are presented to the user. Internally the application only wants to handle their IDs so they are used as the options' value attribute. Let’s see how Rails can help out here.</p></div>
+<h3 id="_the_select_tag_and_options">3.1. The select tag and options</h3>
<div class="paragraph"><p>The most generic helper is <tt>select_tag</tt>, which — as the name implies — simply generates the <tt>SELECT</tt> tag that encapsulates an options string:</p></div>
<div class="listingblock">
<div class="content">
@@ -565,7 +576,7 @@ output: </td>
</tr></table>
</div>
-<h3 id="_select_boxes_for_dealing_with_models">4.2. Select boxes for dealing with models</h3>
+<h3 id="_select_boxes_for_dealing_with_models">3.2. Select boxes for dealing with models</h3>
<div class="paragraph"><p>Until now you’ve seen how to make generic select boxes, but in most cases our form controls will be tied to a specific database model. So, to continue from our previous examples, let’s assume that you have a "Person" model with a <tt>city_id</tt> attribute.</p></div>
<div class="paragraph"><p>Consistent with other form helpers, when dealing with models you drop the <tt>_tag</tt> suffix from <tt>select_tag</tt>.</p></div>
<div class="listingblock">
@@ -598,7 +609,7 @@ output: </td>
</tr></table>
</div>
-<h3 id="_option_tags_from_a_collection_of_arbitrary_objects">4.3. Option tags from a collection of arbitrary objects</h3>
+<h3 id="_option_tags_from_a_collection_of_arbitrary_objects">3.3. Option tags from a collection of arbitrary objects</h3>
<div class="paragraph"><p>Until now you were generating option tags from nested arrays with the help of <tt>options_for_select</tt> method. Data in our array were raw values:</p></div>
<div class="listingblock">
<div class="content">
@@ -621,16 +632,16 @@ output: <pre><tt><%= collection_select(:person, :city_id, City.all, :id, :name) %></tt></pre>
</div></div>
<div class="paragraph"><p>To recap, <tt>options_from_collection_for_select</tt> is to <tt>collection_select</tt> what <tt>options_for_select</tt> is to <tt>select</tt>.</p></div>
-<h3 id="_time_zone_and_country_select">4.4. Time zone and country select</h3>
+<h3 id="_time_zone_and_country_select">3.4. Time zone and country select</h3>
<div class="paragraph"><p>To leverage time zone support in Rails, you have to ask our users what time zone they are in. Doing so would require generating select options from a list of pre-defined TimeZone objects using <tt>collection_select</tt>, but you can simply use the <tt>time_zone_select</tt> helper that already wraps this:</p></div>
<div class="listingblock">
<div class="content">
<pre><tt><%= time_zone_select(:person, :city_id) %></tt></pre>
</div></div>
<div class="paragraph"><p>There is also <tt>time_zone_options_for_select</tt> helper for a more manual (therefore more customizable) way of doing this. Read the API documentation to learn about the possible arguments for these two methods.</p></div>
-<div class="paragraph"><p>Rails <em>used</em> to have a <tt>country_select</tt> helper for choosing countries but this has been extracted to the <a href="http://github.com/rails/country_select/tree/master">country_select plugin</a>. When using this do be aware that the exclusion or inclusion of certain names from the list can be somewhat controversial (and was the reason this functionality was extracted from rails)</p></div>
+<div class="paragraph"><p>Rails <em>used</em> to have a <tt>country_select</tt> helper for choosing countries but this has been extracted to the <a href="http://github.com/rails/country_select/tree/master">country_select plugin</a>. When using this do be aware that the exclusion or inclusion of certain names from the list can be somewhat controversial (and was the reason this functionality was extracted from rails).</p></div>
</div>
-<h2 id="_date_and_time_select_boxes">5. Date and time select boxes</h2>
+<h2 id="_using_date_and_time_form_helpers">4. Using Date and Time Form Helpers</h2>
<div class="sectionbody">
<div class="paragraph"><p>The date and time helpers differ from all the other form helpers in two important respects:</p></div>
<div class="olist arabic"><ol class="arabic">
@@ -646,7 +657,7 @@ Other helpers use the _tag suffix to indicate whether a helper is a barebones he </li>
</ol></div>
<div class="paragraph"><p>Both of these families of helpers will create a series of select boxes for the different components (year, month, day etc...).</p></div>
-<h3 id="_barebones_helpers_2">5.1. Barebones helpers</h3>
+<h3 id="_barebones_helpers">4.1. Barebones helpers</h3>
<div class="paragraph"><p>The <tt>select_*</tt> family of helpers take as their first argument an instance of Date, Time or DateTime that is used as the currently selected value. You may omit this parameter, in which case the current date is used. For example</p></div>
<div class="listingblock">
<div class="content">
@@ -665,7 +676,7 @@ Other helpers use the _tag suffix to indicate whether a helper is a barebones he <pre><tt>Date::civil(params[:start_date][:year].to_i, params[:start_date][:month].to_i, params[:start_date][:day].to_i)</tt></pre>
</div></div>
<div class="paragraph"><p>The :prefix option controls where in the params hash the date components will be placed. Here it was set to <tt>start_date</tt>, if omitted it will default to <tt>date</tt>.</p></div>
-<h3 id="_model_object_helpers_2">5.2. Model object helpers</h3>
+<h3 id="_model_object_helpers_2">4.2. Model object helpers</h3>
<div class="paragraph"><p><tt>select_date</tt> does not work well with forms that update or create Active Record objects as Active Record expects each element of the params hash to correspond to one attribute.
The model object helpers for dates and times submit parameters with special names. When Active Record sees parameters with such names it knows they must be combined with the other parameters and given to a constructor appropriate to the column type. For example</p></div>
<div class="listingblock">
@@ -685,7 +696,7 @@ The model object helpers for dates and times submit parameters with special name <pre><tt>{:person => {'birth_date(1i)' => '2008', 'birth_date(2i)' => '11', 'birth_date(3i)' => '22'}}</tt></pre>
</div></div>
<div class="paragraph"><p>When this is passed to <tt>Person.new</tt>, Active Record spots that these parameters should all be used to construct the <tt>birth_date</tt> attribute and uses the suffixed information to determine in which order it should pass these parameters to functions such as <tt>Date::civil</tt>.</p></div>
-<h3 id="_common_options">5.3. Common options</h3>
+<h3 id="_common_options">4.3. Common options</h3>
<div class="paragraph"><p>Both families of helpers use the same core set of functions to generate the individual select tags and so both accept largely the same options. In particular, by default Rails will generate year options 5 years either side of the current year. If this is not an appropriate range, the <tt>:start_year</tt> and <tt>:end_year</tt> options override this. For an exhaustive list of the available options, refer to the <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html">API documentation</a>.</p></div>
<div class="paragraph"><p>As a rule of thumb you should be using <tt>date_select</tt> when working with model objects and <tt>select_date</tt> in others cases, such as a search form which filters results by date.</p></div>
<div class="admonitionblock">
@@ -697,61 +708,7 @@ The model object helpers for dates and times submit parameters with special name </tr></table>
</div>
</div>
-<h2 id="_form_builders">6. Form builders</h2>
-<div class="sectionbody">
-<div class="paragraph"><p>As mentioned previously the object yielded by <tt>form_for</tt> and <tt>fields_for</tt> is an instance of FormBuilder (or a subclass thereof). Form builders encapsulate the notion of displaying a form elements for a single object. While you can of course write helpers for your forms in the usual way you can also subclass FormBuilder and add the helpers there. For example</p></div>
-<div class="listingblock">
-<div class="content">
-<pre><tt><% form_for @person do |f| %>
- <%= text_field_with_label f, :first_name %>
-<% end %></tt></pre>
-</div></div>
-<div class="paragraph"><p>can be replaced with</p></div>
-<div class="listingblock">
-<div class="content">
-<pre><tt><% form_for @person, :builder => LabellingFormBuilder do |f| %>
- <%= f.text_field :first_name %>
-<% end %></tt></pre>
-</div></div>
-<div class="paragraph"><p>by defining a LabellingFormBuilder class similar to the following:</p></div>
-<div class="listingblock">
-<div class="content"><!-- Generator: GNU source-highlight 2.9
-by Lorenzo Bettini
-http://www.lorenzobettini.it
-http://www.gnu.org/software/src-highlite -->
-<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> LabellingFormBuilder <span style="color: #990000"><</span> FormBuilder
- <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> text_field attribute<span style="color: #990000">,</span> options<span style="color: #990000">=</span><span style="color: #FF0000">{}</span>
- label<span style="color: #990000">(</span>attribute<span style="color: #990000">)</span> <span style="color: #990000">+</span> text_field<span style="color: #990000">(</span>attribute<span style="color: #990000">,</span> options<span style="color: #990000">)</span>
- <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
-<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
-<div class="paragraph"><p>If you reuse this frequently you could define a <tt>labeled_form_for</tt> helper that automatically applies the <tt>:builder => LabellingFormBuilder</tt> option.</p></div>
-<div class="paragraph"><p>The form builder used also determines what happens when you do</p></div>
-<div class="listingblock">
-<div class="content">
-<pre><tt><%= render :partial => f %></tt></pre>
-</div></div>
-<div class="paragraph"><p>If <tt>f</tt> is an instance of FormBuilder then this will render the <em>form</em> partial, setting the partial’s object to the form builder. If the form builder is of class LabellingFormBuilder then the <em>labelling_form</em> partial would be rendered instead.</p></div>
-<h3 id="_scoping_out_form_controls_with_tt_fields_for_tt">6.1. Scoping out form controls with <tt>fields_for</tt></h3>
-<div class="paragraph"><p><tt>fields_for</tt> creates a form builder in exactly the same way as <tt>form_for</tt> but doesn’t create the actual <tt><form></tt> tags. It creates a scope around a specific model object like <tt>form_for</tt>, which is useful for specifying additional model objects in the same form. For example if you had a Person model with an associated ContactDetail model you could create a form for editing both like so:</p></div>
-<div class="listingblock">
-<div class="content">
-<pre><tt><% form_for @person do |person_form| %>
- <%= person_form.text_field :name %>
- <% fields_for @person.contact_detail do |contact_details_form| %>
- <%= contact_details_form.text_field :phone_number %>
- <% end %>
-<% end %></tt></pre>
-</div></div>
-<div class="paragraph"><p>which produces the following output:</p></div>
-<div class="listingblock">
-<div class="content">
-<pre><tt><form action="/people/1" class="edit_person" id="edit_person_1" method="post">
- <input id="person_name" name="person[name]" size="30" type="text" />
- <input id="contact_detail_phone_number" name="contact_detail[phone_number]" size="30" type="text" />
-</form></tt></pre>
-</div></div>
-</div>
-<h2 id="_file_uploads">7. File Uploads</h2>
+<h2 id="_uploading_files">5. Uploading Files</h2>
<div class="sectionbody">
<div class="paragraph"><p>A common task is uploading some sort of file, whether it’s a picture of a person or a CSV file containing data to process. The most important thing to remember with file uploads is that the form’s encoding <strong>MUST</strong> be set to multipart/form-data. If you forget to do this the file will not be uploaded. This can be done by passing <tt>:multi_part => true</tt> as an HTML option. This means that in the case of <tt>form_tag</tt> it must be passed in the second options hash and in the case of <tt>form_for</tt> inside the <tt>:html</tt> hash.</p></div>
<div class="paragraph"><p>The following two forms both upload a file.</p></div>
@@ -766,7 +723,7 @@ http://www.gnu.org/software/src-highlite --> <% end %></tt></pre>
</div></div>
<div class="paragraph"><p>Rails provides the usual pair of helpers: the barebones <tt>file_field_tag</tt> and the model oriented <tt>file_field</tt>. The only difference with other helpers is that you cannot set a default value for file inputs as this would have no meaning. As you would expect in the first case the uploaded file is in <tt>params[:picture]</tt> and in the second case in <tt>params[:person][:picture]</tt>.</p></div>
-<h3 id="_what_gets_uploaded">7.1. What gets uploaded</h3>
+<h3 id="_what_gets_uploaded">5.1. What gets uploaded</h3>
<div class="paragraph"><p>The object in the params hash is an instance of a subclass of IO. Depending on the size of the uploaded file it may in fact be a StringIO or an instance of File backed by a temporary file. In both cases the object will have an <tt>original_filename</tt> attribute containing the name the file had on the user’s computer and a <tt>content_type</tt> attribute containing the MIME type of the uploaded file. The following snippet saves the uploaded content in <tt>#{RAILS_ROOT}/public/uploads</tt> under the same name as the original file (assuming the form was the one in the previous example).</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
@@ -788,14 +745,49 @@ http://www.gnu.org/software/src-highlite --> <td class="content">If the user has not selected a file the corresponding parameter will be an empty string.</td>
</tr></table>
</div>
-<h3 id="_dealing_with_ajax">7.2. Dealing with Ajax</h3>
+<h3 id="_dealing_with_ajax">5.2. Dealing with Ajax</h3>
<div class="paragraph"><p>Unlike other forms making an asynchronous file upload form is not as simple as replacing <tt>form_for</tt> with <tt>remote_form_for</tt>. With an AJAX form the serialization is done by javascript running inside the browser and since javascript cannot read files from your hard drive the file cannot be uploaded. The most common workaround is to use an invisible iframe that serves as the target for the form submission.</p></div>
</div>
-<h2 id="_parameter_names">8. Parameter Names</h2>
+<h2 id="_customising_form_builders">6. Customising Form Builders</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>As mentioned previously the object yielded by <tt>form_for</tt> and <tt>fields_for</tt> is an instance of FormBuilder (or a subclass thereof). Form builders encapsulate the notion of displaying a form elements for a single object. While you can of course write helpers for your forms in the usual way you can also subclass FormBuilder and add the helpers there. For example</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt><% form_for @person do |f| %>
+ <%= text_field_with_label f, :first_name %>
+<% end %></tt></pre>
+</div></div>
+<div class="paragraph"><p>can be replaced with</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt><% form_for @person, :builder => LabellingFormBuilder do |f| %>
+ <%= f.text_field :first_name %>
+<% end %></tt></pre>
+</div></div>
+<div class="paragraph"><p>by defining a LabellingFormBuilder class similar to the following:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> LabellingFormBuilder <span style="color: #990000"><</span> FormBuilder
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> text_field attribute<span style="color: #990000">,</span> options<span style="color: #990000">=</span><span style="color: #FF0000">{}</span>
+ label<span style="color: #990000">(</span>attribute<span style="color: #990000">)</span> <span style="color: #990000">+</span> text_field<span style="color: #990000">(</span>attribute<span style="color: #990000">,</span> options<span style="color: #990000">)</span>
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
+<div class="paragraph"><p>If you reuse this frequently you could define a <tt>labeled_form_for</tt> helper that automatically applies the <tt>:builder => LabellingFormBuilder</tt> option.</p></div>
+<div class="paragraph"><p>The form builder used also determines what happens when you do</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><tt><%= render :partial => f %></tt></pre>
+</div></div>
+<div class="paragraph"><p>If <tt>f</tt> is an instance of FormBuilder then this will render the <em>form</em> partial, setting the partial’s object to the form builder. If the form builder is of class LabellingFormBuilder then the <em>labelling_form</em> partial would be rendered instead.</p></div>
+</div>
+<h2 id="_understanding_parameter_naming_conventions">7. Understanding Parameter Naming Conventions</h2>
<div class="sectionbody">
-<div class="paragraph" id="parameter_names"><p>As you’ve seen in the previous sections values from forms can appear either at the top level of the params hash or may appear nested in another hash. For example in a standard create
+<div class="paragraph" id="parameter_names"><p>As you’ve seen in the previous sections, values from forms can appear either at the top level of the params hash or may appear nested in another hash. For example in a standard create
action for a Person model, <tt>params[:model]</tt> would usually be a hash of all the attributes for the person to create. The params hash can also contain arrays, arrays of hashes and so on.</p></div>
-<div class="paragraph"><p>Fundamentally HTML forms don’t know about any sort of structured data. All they know about is name-value pairs. Rails tacks some conventions onto parameter names which it uses to express some structure.</p></div>
+<div class="paragraph"><p>Fundamentally HTML forms don’t know about any sort of structured data, all they generate is name-value pairs. The arrays and hashes you see in your application are the result of some parameter naming conventions that Rails uses.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
@@ -811,7 +803,7 @@ action for a Person model, <tt>params[:model]</tt> would usually be a hash of al </td>
</tr></table>
</div>
-<h3 id="_basic_structures">8.1. Basic structures</h3>
+<h3 id="_basic_structures">7.1. Basic structures</h3>
<div class="paragraph"><p>The two basic structures are arrays and hashes. Hashes mirror the syntax used for accessing the value in the params. For example if a form contains</p></div>
<div class="listingblock">
<div class="content">
@@ -845,7 +837,7 @@ http://www.gnu.org/software/src-highlite --> <input name="person[phone_number][]" type="text"/></tt></pre>
</div></div>
<div class="paragraph"><p>This would result in <tt>params[:person][:phone_number]</tt> being an array.</p></div>
-<h3 id="_combining_them">8.2. Combining them</h3>
+<h3 id="_combining_them">7.2. Combining them</h3>
<div class="paragraph"><p>We can mix and match these two concepts. For example, one element of a hash might be an array as in the previous example, or you can have an array of hashes. For example a form might let you create any number of addresses by repeating the following form fragment</p></div>
<div class="listingblock">
<div class="content">
@@ -863,7 +855,7 @@ http://www.gnu.org/software/src-highlite --> <td class="content">Array parameters do not play well with the <tt>check_box</tt> helper. According to the HTML specification unchecked checkboxes submit no value. However it is often convenient for a checkbox to always submit a value. The <tt>check_box</tt> helper fakes this by creating a second hidden input with the same name. If the checkbox is unchecked only the hidden input is submitted. If the checkbox is checked then both are submitted but the value submitted by the checkbox takes precedence. When working with array parameters this duplicate submission will confuse Rails since duplicate input names are how it decides when to start a new hash. It is preferable to either use <tt>check_box_tag</tt> or to use hashes instead of arrays.</td>
</tr></table>
</div>
-<h3 id="_using_form_helpers">8.3. Using form helpers</h3>
+<h3 id="_using_form_helpers">7.3. Using form helpers</h3>
<div class="paragraph"><p>The previous sections did not use the Rails form helpers at all. While you can craft the input names yourself and pass them directly to helpers such as <tt>text_field_tag</tt> Rails also provides higher level support. The two tools at your disposal here are the name parameter to <tt>form_for</tt>/<tt>fields_for</tt> and the <tt>:index</tt> option.</p></div>
<div class="paragraph"><p>You might want to render a form with a set of edit fields for each of a person’s addresses. Something a little like this will do the trick</p></div>
<div class="listingblock">
@@ -916,7 +908,7 @@ http://www.gnu.org/software/src-highlite --> </div></div>
<div class="paragraph"><p>produces exactly the same output as the previous example.</p></div>
</div>
-<h2 id="_complex_forms">9. Complex forms</h2>
+<h2 id="_building_complex_forms">8. Building Complex forms</h2>
<div class="sectionbody">
<div class="paragraph"><p>Many apps grow beyond simple forms editing a single object. For example when creating a Person instance you might want to allow the user to (on the same form) create multiple address records (home, work etc.). When later editing that person the user should be able to add, remove or amend addresses as necessary. While this guide has shown you all the pieces necessary to handle this, Rails does not yet have a standard end-to-end way of accomplishing this, but many have come up with viable approaches. These include:</p></div>
<div class="ulist"><ul>
@@ -947,7 +939,7 @@ James Golick’s <a href="http://github.com/giraffesoft/attribute_fu/tree">a </li>
</ul></div>
</div>
-<h2 id="_changelog">10. Changelog</h2>
+<h2 id="_changelog">9. Changelog</h2>
<div class="sectionbody">
<div class="paragraph"><p><a href="http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/1">Lighthouse ticket</a></p></div>
<div class="ulist"><div class="title">Authors</div><ul>
diff --git a/railties/doc/guides/html/i18n.html b/railties/doc/guides/html/i18n.html index 8a6e4cc990..386b801d64 100644 --- a/railties/doc/guides/html/i18n.html +++ b/railties/doc/guides/html/i18n.html @@ -50,6 +50,10 @@ <li><a href="#_setting_and_passing_the_locale">Setting and passing the locale</a></li> + <li><a href="#_setting_locale_from_the_domain_name">Setting locale from the domain name</a></li> + + <li><a href="#_setting_locale_from_the_url_params">Setting locale from the URL params</a></li> + </ul> </li> <li> @@ -80,9 +84,9 @@ <a href="#_how_to_store_your_custom_translations">How to store your custom translations</a> <ul> - <li><a href="#_translations_for_activerecord_models">Translations for ActiveRecord models</a></li> + <li><a href="#_translations_for_active_record_models">Translations for Active Record models</a></li> - <li><a href="#_other_translations_and_localizations">Other translations and localizations</a></li> + <li><a href="#_overview_of_other_built_in_methods_that_provide_i18n_support">Overview of other built-in methods that provide I18n support</a></li> </ul> </li> @@ -97,9 +101,18 @@ </ul> </li> <li> + <a href="#_conclusion">Conclusion</a> + </li> + <li> + <a href="#_contributing_to_rails_i18n">Contributing to Rails I18n</a> + </li> + <li> <a href="#_resources">Resources</a> </li> <li> + <a href="#_authors">Authors</a> + </li> + <li> <a href="#_footnotes">Footnotes</a> </li> <li> @@ -138,7 +151,7 @@ making it easy to customize and extend everything for other languages </p>
</li>
</ul></div>
-<div class="paragraph"><p>As part of this solution, <strong>every static string in the Rails framework</strong> — eg. ActiveRecord validation messages, time and date formats — <strong>has been internationalized</strong>, so <em>localization</em> of a Rails application means "over-riding" these defaults.</p></div>
+<div class="paragraph"><p>As part of this solution, <strong>every static string in the Rails framework</strong> — eg. Active Record validation messages, time and date formats — <strong>has been internationalized</strong>, so <em>localization</em> of a Rails application means "over-riding" these defaults.</p></div>
<h3 id="_the_overall_architecture_of_the_library">1.1. The overall architecture of the library</h3>
<div class="paragraph"><p>Thus, the Ruby I18n gem is split into two parts:</p></div>
<div class="ulist"><ul>
@@ -206,7 +219,7 @@ http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
<pre><tt>en<span style="color: #990000">:</span>
hello<span style="color: #990000">:</span> <span style="color: #FF0000">"Hello world"</span></tt></pre></div></div>
-<div class="paragraph"><p>This means, that in the <tt>:en</tt> locale, the key <em>hello</em> will map to <em>Hello world</em> string. Every string inside Rails is internationalized in this way, see for instance ActiveRecord validation messages in the <a href="http://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml"><tt>activerecord/lib/active_record/locale/en.yml</tt></a> file or time and date formats in the <a href="http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml"><tt>activesupport/lib/active_support/locale/en.yml</tt></a> file. You can use YAML or standard Ruby Hashes to store translations in the default (Simple) backend.</p></div>
+<div class="paragraph"><p>This means, that in the <tt>:en</tt> locale, the key <em>hello</em> will map to <em>Hello world</em> string. Every string inside Rails is internationalized in this way, see for instance Active Record validation messages in the <a href="http://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml"><tt>activerecord/lib/active_record/locale/en.yml</tt></a> file or time and date formats in the <a href="http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml"><tt>activesupport/lib/active_support/locale/en.yml</tt></a> file. You can use YAML or standard Ruby Hashes to store translations in the default (Simple) backend.</p></div>
<div class="paragraph"><p>The I18n library will use <strong>English</strong> as a <strong>default locale</strong>, ie. if you don’t set a different locale, <tt>:en</tt> will be used for looking up translations.</p></div>
<div class="paragraph"><p>The <strong>translations load path</strong> (<tt>I18n.load_path</tt>) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you.</p></div>
<div class="admonitionblock">
@@ -244,8 +257,17 @@ I18n<span style="color: #990000">.</span>load_path <span style="color: #990000"> <span style="font-style: italic"><span style="color: #9A1900"># set default locale to something else then :en</span></span>
I18n<span style="color: #990000">.</span>default_locale <span style="color: #990000">=</span> <span style="color: #990000">:</span>pt</tt></pre></div></div>
<h3 id="_setting_and_passing_the_locale">2.3. Setting and passing the locale</h3>
-<div class="paragraph"><p>By default the I18n library will use :en (English) as a I18n.default_locale for looking up translations (if you do not specify a locale for a lookup).</p></div>
-<div class="paragraph"><p>If you want to translate your Rails application to a single language other than English you can set I18n.default_locale to your locale. If you want to change the locale on a per-request basis though you can set it in a before_filter on the ApplicationController like this:</p></div>
+<div class="paragraph"><p>If you want to translate your Rails application to a <strong>single language other than English</strong> (the default locale), you can set I18n.default_locale to your locale in <tt>environment.rb</tt> or an initializer as shown above, and it will persist through the requests.</p></div>
+<div class="paragraph"><p>However, you would probably like to <strong>provide support for more locales</strong> in your application. In such case, you need to set and pass the locale between requests.</p></div>
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<img src="./images/icons/warning.png" alt="Warning" />
+</td>
+<td class="content">You may be tempted to store choosed locale in a <em>session</em> or a <em>cookie</em>. <strong>Do not do so</strong>. The locale should be transparent and a part of the URL. This way you don’t break people’s basic assumptions about the web itself: if you send a URL of some page to a friend, she should see the same page, same content. A fancy word for this would be that you’re being <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer"><em>RESTful</em></a>. There may be some exceptions to this rule, which are discussed below.</td>
+</tr></table>
+</div>
+<div class="paragraph"><p>The <em>setting part</em> is easy. You can set locale in a <tt>before_filter</tt> in the ApplicationController like this:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
by Lorenzo Bettini
@@ -253,16 +275,131 @@ http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
<pre><tt>before_filter <span style="color: #990000">:</span>set_locale
<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> set_locale
- <span style="font-style: italic"><span style="color: #9A1900"># if this is nil then I18n.default_locale will be used</span></span>
+ <span style="font-style: italic"><span style="color: #9A1900"># if params[:locale] is nil then I18n.default_locale will be used</span></span>
I18n<span style="color: #990000">.</span>locale <span style="color: #990000">=</span> params<span style="color: #990000">[:</span>locale<span style="color: #990000">]</span>
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
-<div class="paragraph"><p>This will already work for URLs where you pass the locale as a query parameter as in example.com?locale=pt (which is what Google also does).</p></div>
+<div class="paragraph"><p>This requires you to pass the locale as a URL query parameter as in <tt>http://example.com/books?locale=pt</tt>. (This is eg. Google’s approach). So <tt>http://localhost:3000?locale=pt</tt> will load the Portugese localization, whereas <tt>http://localhost:3000?locale=de</tt> would load the German localization, and so on.</p></div>
+<div class="paragraph"><p>Of course, you probably don’t want to manually include locale in every URL all over your application, or want the URLs look differently, eg. the usual <tt>http://example.com/pt/books</tt> versus <tt>http://example.com/en/books</tt>. Let’s discuss the different options you have.</p></div>
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<img src="./images/icons/important.png" alt="Important" />
+</td>
+<td class="content">Following examples rely on having locales loaded into your application available as an array of strings like <tt>["en", "es", "gr"]</tt>. This is not inclued in current version of Rails 2.2 — forthcoming Rails version 2.3 will contain easy accesor <tt>available_locales</tt>. (See <a href="http://github.com/svenfuchs/i18n/commit/411f8fe7">this commit</a> and background at <a href="http://rails-i18n.org/wiki/pages/i18n-available_locales">Rails I18n Wiki</a>.)</td>
+</tr></table>
+</div>
+<div class="paragraph"><p>We have to include support for getting available locales manually in an initializer like this:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-style: italic"><span style="color: #9A1900"># config/initializers/available_locales.rb</span></span>
+<span style="font-style: italic"><span style="color: #9A1900">#</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># Get loaded locales conveniently</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># See http://rails-i18n.org/wiki/pages/i18n-available_locales</span></span>
+<span style="font-weight: bold"><span style="color: #0000FF">module</span></span> I18n
+ <span style="font-weight: bold"><span style="color: #0000FF">class</span></span> <span style="color: #990000"><<</span> <span style="font-weight: bold"><span style="color: #0000FF">self</span></span>
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> available_locales<span style="color: #990000">;</span> backend<span style="color: #990000">.</span>available_locales<span style="color: #990000">;</span> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+ <span style="font-weight: bold"><span style="color: #0000FF">module</span></span> Backend
+ <span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Simple
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> available_locales<span style="color: #990000">;</span> translations<span style="color: #990000">.</span>keys<span style="color: #990000">.</span>collect <span style="color: #FF0000">{</span> <span style="color: #990000">|</span>l<span style="color: #990000">|</span> l<span style="color: #990000">.</span>to_s <span style="color: #FF0000">}</span><span style="color: #990000">.</span>sort<span style="color: #990000">;</span> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+
+<span style="font-style: italic"><span style="color: #9A1900"># You need to "force-initialize" loaded locales</span></span>
+I18n<span style="color: #990000">.</span>backend<span style="color: #990000">.</span>send<span style="color: #990000">(:</span>init_translations<span style="color: #990000">)</span>
+
+AVAILABLE_LOCALES <span style="color: #990000">=</span> I18n<span style="color: #990000">.</span>backend<span style="color: #990000">.</span>available_locales
+RAILS_DEFAULT_LOGGER<span style="color: #990000">.</span>debug <span style="color: #FF0000">"* Loaded locales: #{AVAILABLE_LOCALES.inspect}"</span></tt></pre></div></div>
+<div class="paragraph"><p>You can then wrap the constant for easy access in ApplicationController:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> ApplicationController <span style="color: #990000"><</span> ActionController<span style="color: #990000">::</span>Base
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> available_locales<span style="color: #990000">;</span> AVAILABLE_LOCALES<span style="color: #990000">;</span> <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
+<h3 id="_setting_locale_from_the_domain_name">2.4. Setting locale from the domain name</h3>
+<div class="paragraph"><p>One option you have is to set the locale from the domain name, where your application runs. For example, we want <tt>www.example.com</tt> to load English (or default) locale, and <tt>www.example.es</tt> to load Spanish locale. Thus the <em>top-level domain name</em> is used for locale setting. This has several advantages:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Locale is an <em>obvious</em> part of the URL
+</p>
+</li>
+<li>
+<p>
+People intuitively grasp in which language the content will be displayed
+</p>
+</li>
+<li>
+<p>
+It is very trivial to implement in Rails
+</p>
+</li>
+<li>
+<p>
+Search engines seem to like that content in different languages lives at different, inter-linked domains
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>You can implement it like this in your ApplicationController:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt>before_filter <span style="color: #990000">:</span>set_locale
+<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> set_locale
+ I18n<span style="color: #990000">.</span>locale <span style="color: #990000">=</span> extract_locale_from_uri
+<span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># Get locale from top-level domain or return nil if such locale is not available</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># You have to put something like:</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># 127.0.0.1 application.com</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># 127.0.0.1 application.it</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># 127.0.0.1 application.pl</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># in your /etc/hosts file to try this out locally</span></span>
+<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> extract_locale_from_tld
+ parsed_locale <span style="color: #990000">=</span> request<span style="color: #990000">.</span>host<span style="color: #990000">.</span>split<span style="color: #990000">(</span><span style="color: #FF0000">'.'</span><span style="color: #990000">).</span>last
+ <span style="color: #990000">(</span>available_locales<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #0000FF">include</span></span><span style="color: #990000">?</span> parsed_locale<span style="color: #990000">)</span> <span style="color: #990000">?</span> parsed_locale <span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">nil</span></span>
+<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
+<div class="paragraph"><p>We can also set the locale from the <em>subdomain</em> in very similar way:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 2.9
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-style: italic"><span style="color: #9A1900"># Get locale code from request subdomain (like http://it.application.local:3000)</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># You have to put something like:</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># 127.0.0.1 gr.application.local</span></span>
+<span style="font-style: italic"><span style="color: #9A1900"># in your /etc/hosts file to try this out locally</span></span>
+<span style="font-weight: bold"><span style="color: #0000FF">def</span></span> extract_locale_from_subdomain
+ parsed_locale <span style="color: #990000">=</span> request<span style="color: #990000">.</span>subdomains<span style="color: #990000">.</span>first
+ <span style="color: #990000">(</span>available_locales<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #0000FF">include</span></span><span style="color: #990000">?</span> parsed_locale<span style="color: #990000">)</span> <span style="color: #990000">?</span> parsed_locale <span style="color: #990000">:</span> <span style="font-weight: bold"><span style="color: #0000FF">nil</span></span>
+<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
+<h3 id="_setting_locale_from_the_url_params">2.5. Setting locale from the URL params</h3>
+<div class="ulist"><ul>
+<li>
+<p>
+TODO : Based on <strong><tt>default_url options</tt></strong>, <a href="http://github.com/karmi/test_default_url_options/blob/master/app/controllers/application.rb#L22-26">http://github.com/karmi/test_default_url_options/blob/master/app/controllers/application.rb#L22-26</a>
+</p>
+</li>
+<li>
+<p>
+TODO : Discussion of plugins (translate_routes and routing_filter)
+</p>
+</li>
+</ul></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<img src="./images/icons/tip.png" alt="Tip" />
</td>
-<td class="content">For other URL designs, see <a href="http://rails-i18n.org/wiki/pages/how-to-encode-the-current-locale-in-the-url">How to encode the current locale in the URL</a>.</td>
+<td class="content">For setting locale from URL see <a href="http://rails-i18n.org/wiki/pages/how-to-encode-the-current-locale-in-the-url">How to encode the current locale in the URL</a> in the Rails i18n Wiki.</td>
</tr></table>
</div>
<div class="paragraph"><p>Now you’ve initialized I18n support for your application and told it which locale should be used. With that in place you’re now ready for the really interesting stuff.</p></div>
@@ -340,7 +477,7 @@ pirate<span style="color: #990000">:</span> hello_flash<span style="color: #990000">:</span> Ahoy Flash</tt></pre></div></div>
<div class="paragraph"><p>There you go. Because you haven’t changed the default_locale I18n will use English. Your application now shows:</p></div>
<div class="paragraph"><p><span class="image">
-<img src="images/i18n/demo_translated_english.png" alt="rails i18n demo translated to english" title="rails i18n demo translated to english" />
+<img src="images/i18n/demo_translated_en.png" alt="rails i18n demo translated to english" title="rails i18n demo translated to english" />
</span></p></div>
<div class="paragraph"><p>And when you change the URL to pass the pirate locale you get:</p></div>
<div class="paragraph"><p><span class="image">
@@ -417,7 +554,7 @@ by Lorenzo Bettini http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt>I18n<span style="color: #990000">.</span>t <span style="color: #990000">:</span>invalid<span style="color: #990000">,</span> <span style="color: #990000">:</span>scope <span style="color: #990000">=></span> <span style="color: #990000">[:</span>active_record<span style="color: #990000">,</span> <span style="color: #990000">:</span>error_messages<span style="color: #990000">]</span></tt></pre></div></div>
-<div class="paragraph"><p>This looks up the :invalid message in the ActiveRecord error messages.</p></div>
+<div class="paragraph"><p>This looks up the :invalid message in the Active Record error messages.</p></div>
<div class="paragraph"><p>Additionally, both the key and scopes can be specified as dot separated keys as in:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
@@ -462,7 +599,7 @@ http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
<pre><tt>I18n<span style="color: #990000">.</span>t <span style="color: #990000">[:</span>odd<span style="color: #990000">,</span> <span style="color: #990000">:</span>even<span style="color: #990000">],</span> <span style="color: #990000">:</span>scope <span style="color: #990000">=></span> <span style="color: #FF0000">'active_record.error_messages'</span>
<span style="font-style: italic"><span style="color: #9A1900"># => ["must be odd", "must be even"]</span></span></tt></pre></div></div>
-<div class="paragraph"><p>Also, a key can translate to a (potentially nested) hash as grouped translations. E.g. one can receive all ActiveRecord error messages as a Hash with:</p></div>
+<div class="paragraph"><p>Also, a key can translate to a (potentially nested) hash as grouped translations. E.g. one can receive all Active Record error messages as a Hash with:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
by Lorenzo Bettini
@@ -581,7 +718,7 @@ I18n<span style="color: #990000">.</span>t <span style="color: #FF0000">'formats I18n<span style="color: #990000">.</span>t <span style="color: #990000">:</span>short<span style="color: #990000">,</span> <span style="color: #990000">:</span>scope <span style="color: #990000">=></span> <span style="color: #FF0000">'date.formats'</span>
I18n<span style="color: #990000">.</span>t <span style="color: #990000">:</span>short<span style="color: #990000">,</span> <span style="color: #990000">:</span>scope <span style="color: #990000">=></span> <span style="color: #990000">[:</span>date<span style="color: #990000">,</span> <span style="color: #990000">:</span>formats<span style="color: #990000">]</span></tt></pre></div></div>
<div class="paragraph"><p>Generally we recommend using YAML as a format for storing translations. There are cases though where you want to store Ruby lambdas as part of your locale data, e.g. for special date</p></div>
-<h3 id="_translations_for_activerecord_models">5.1. Translations for ActiveRecord models</h3>
+<h3 id="_translations_for_active_record_models">5.1. Translations for Active Record models</h3>
<div class="paragraph"><p>You can use the methods Model.human_name and Model.human_attribute_name(attribute) to transparently lookup translations for your model and attribute names.</p></div>
<div class="paragraph"><p>For example when you add the following translations:</p></div>
<div class="listingblock">
@@ -599,7 +736,7 @@ http://www.gnu.org/software/src-highlite --> <span style="font-style: italic"><span style="color: #9A1900"># will translate User attribute "login" as "Handle"</span></span></tt></pre></div></div>
<div class="paragraph"><p>Then User.human_name will return "Dude" and User.human_attribute_name(:login) will return "Handle".</p></div>
<h4 id="_error_message_scopes">5.1.1. Error message scopes</h4>
-<div class="paragraph"><p>ActiveRecord validation error messages can also be translated easily. ActiveRecord gives you a couple of namespaces where you can place your message translations in order to provide different messages and translation for certain models, attributes and/or validations. It also transparently takes single table inheritance into account.</p></div>
+<div class="paragraph"><p>Active Record validation error messages can also be translated easily. Active Record gives you a couple of namespaces where you can place your message translations in order to provide different messages and translation for certain models, attributes and/or validations. It also transparently takes single table inheritance into account.</p></div>
<div class="paragraph"><p>This gives you quite powerful means to flexibly adjust your messages to your application’s needs.</p></div>
<div class="paragraph"><p>Consider a User model with a validates_presence_of validation for the name attribute like this:</p></div>
<div class="listingblock">
@@ -610,7 +747,7 @@ http://www.gnu.org/software/src-highlite --> <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> User <span style="color: #990000"><</span> ActiveRecord<span style="color: #990000">::</span>Base
validates_presence_of <span style="color: #990000">:</span>name
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
-<div class="paragraph"><p>The key for the error message in this case is :blank. ActiveRecord will lookup this key in the namespaces:</p></div>
+<div class="paragraph"><p>The key for the error message in this case is :blank. Active Record will lookup this key in the namespaces:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
by Lorenzo Bettini
@@ -638,7 +775,7 @@ http://www.gnu.org/software/src-highlite --> <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Admin <span style="color: #990000"><</span> User
validates_presence_of <span style="color: #990000">:</span>name
<span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
-<div class="paragraph"><p>Then ActiveRecord will look for messages in this order:</p></div>
+<div class="paragraph"><p>Then Active Record will look for messages in this order:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
by Lorenzo Bettini
@@ -756,6 +893,36 @@ cellspacing="0" cellpadding="4"> </tr>
<tr>
<td align="left"><p class="table">validates_numericality_of</p></td>
+<td align="left"><p class="table">:greater_than</p></td>
+<td align="left"><p class="table">:greater_than</p></td>
+<td align="left"><p class="table">value</p></td>
+</tr>
+<tr>
+<td align="left"><p class="table">validates_numericality_of</p></td>
+<td align="left"><p class="table">:greater_than_or_equal_to</p></td>
+<td align="left"><p class="table">:greater_than_or_equal_to</p></td>
+<td align="left"><p class="table">value</p></td>
+</tr>
+<tr>
+<td align="left"><p class="table">validates_numericality_of</p></td>
+<td align="left"><p class="table">:equal_to</p></td>
+<td align="left"><p class="table">:equal_to</p></td>
+<td align="left"><p class="table">value</p></td>
+</tr>
+<tr>
+<td align="left"><p class="table">validates_numericality_of</p></td>
+<td align="left"><p class="table">:less_than</p></td>
+<td align="left"><p class="table">:less_than</p></td>
+<td align="left"><p class="table">value</p></td>
+</tr>
+<tr>
+<td align="left"><p class="table">validates_numericality_of</p></td>
+<td align="left"><p class="table">:less_than_or_equal_to</p></td>
+<td align="left"><p class="table">:less_than_or_equal_to</p></td>
+<td align="left"><p class="table">value</p></td>
+</tr>
+<tr>
+<td align="left"><p class="table">validates_numericality_of</p></td>
<td align="left"><p class="table">:odd</p></td>
<td align="left"><p class="table">:odd</p></td>
<td align="left"><p class="table">value</p></td>
@@ -769,8 +936,8 @@ cellspacing="0" cellpadding="4"> </tbody>
</table>
</div>
-<h4 id="_translations_for_the_activerecord_error_messages_for_helper">5.1.3. Translations for the ActiveRecord error_messages_for helper</h4>
-<div class="paragraph"><p>If you are using the ActiveRecord error_messages_for helper you will want to add translations for it.</p></div>
+<h4 id="_translations_for_the_active_record_error_messages_for_helper">5.1.3. Translations for the Active Record error_messages_for helper</h4>
+<div class="paragraph"><p>If you are using the Active Record error_messages_for helper you will want to add translations for it.</p></div>
<div class="paragraph"><p>Rails ships with the following translations:</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 2.9
@@ -785,9 +952,52 @@ http://www.gnu.org/software/src-highlite --> one<span style="color: #990000">:</span> <span style="color: #FF0000">"1 error prohibited this {{model}} from being saved"</span>
other<span style="color: #990000">:</span> <span style="color: #FF0000">"{{count}} errors prohibited this {{model}} from being saved"</span>
body<span style="color: #990000">:</span> <span style="color: #FF0000">"There were problems with the following fields:"</span></tt></pre></div></div>
-<h3 id="_other_translations_and_localizations">5.2. Other translations and localizations</h3>
-<div class="paragraph"><p>Rails uses fixed strings and other localizations, such as format strings and other format information in a couple of helpers.</p></div>
-<div class="paragraph"><p>TODO list helpers and available keys</p></div>
+<h3 id="_overview_of_other_built_in_methods_that_provide_i18n_support">5.2. Overview of other built-in methods that provide I18n support</h3>
+<div class="paragraph"><p>Rails uses fixed strings and other localizations, such as format strings and other format information in a couple of helpers. Here’s a brief overview.</p></div>
+<h4 id="_actionview_helper_methods">5.2.1. ActionView helper methods</h4>
+<div class="ulist"><ul>
+<li>
+<p>
+distance_of_time_in_words translates and pluralizes its result and interpolates the number of seconds, minutes, hours and so on. See <a href="http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L51">datetime.distance_in_words</a> translations.
+</p>
+</li>
+<li>
+<p>
+datetime_select and select_month use translated month names for populating the resulting select tag. See <a href="http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L15">date.month_names</a> for translations. datetime_select also looks up the order option from <a href="http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L18">date.order</a> (unless you pass the option explicitely). All date select helpers translate the prompt using the translations in the <a href="http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L83">datetime.prompts</a> scope if applicable.
+</p>
+</li>
+<li>
+<p>
+The number_to_currency, number_with_precision, number_to_percentage, number_with_delimiter and humber_to_human_size helpers use the number format settings located in the <a href="http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L2">number</a> scope.
+</p>
+</li>
+</ul></div>
+<h4 id="_active_record_methods">5.2.2. Active Record methods</h4>
+<div class="ulist"><ul>
+<li>
+<p>
+human_name and human_attribute_name use translations for model names and attribute names if available in the <a href="http://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml#L43">activerecord.models</a> scope. They also support translations for inherited class names (e.g. for use with STI) as explained above in "Error message scopes".
+</p>
+</li>
+<li>
+<p>
+ActiveRecord::Errors#generate_message (which is used by Active Record validations but may also be used manually) uses human_name and human_attribute_name (see above). It also translates the error message and supports translations for inherited class names as explained above in "Error message scopes".
+</p>
+</li>
+<li>
+<p>
+ActiveRecord::Errors#full_messages prepends the attribute name to the error message using a separator that will be looked up from <a href="http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L91">activerecord.errors.format.separator</a> (and defaults to ' ').
+</p>
+</li>
+</ul></div>
+<h4 id="_activesupport_methods">5.2.3. ActiveSupport methods</h4>
+<div class="ulist"><ul>
+<li>
+<p>
+Array#to_sentence uses format settings as given in the <a href="http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L30">support.array</a> scope.
+</p>
+</li>
+</ul></div>
</div>
<h2 id="_customize_your_i18n_setup">6. Customize your I18n setup</h2>
<div class="sectionbody">
@@ -838,16 +1048,75 @@ http://www.lorenzobettini.it http://www.gnu.org/software/src-highlite -->
<pre><tt>I18n<span style="color: #990000">.</span>t <span style="color: #990000">:</span>foo<span style="color: #990000">,</span> <span style="color: #990000">:</span><span style="font-weight: bold"><span style="color: #0000FF">raise</span></span> <span style="color: #990000">=></span> <span style="font-weight: bold"><span style="color: #0000FF">true</span></span> <span style="font-style: italic"><span style="color: #9A1900"># always re-raises exceptions from the backend</span></span></tt></pre></div></div>
</div>
-<h2 id="_resources">7. Resources</h2>
+<h2 id="_conclusion">7. Conclusion</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>At this point you hopefully have a good overview about how I18n support in Ruby on Rails works and are ready to start translating your project.</p></div>
+<div class="paragraph"><p>If you find anything missing or wrong in this guide please file a ticket on <a href="http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview">our issue tracker</a>. If you want to discuss certain portions or have questions please sign up to our <a href="http://groups.google.com/group/rails-i18n">mailinglist</a>.</p></div>
+</div>
+<h2 id="_contributing_to_rails_i18n">8. Contributing to Rails I18n</h2>
<div class="sectionbody">
+<div class="paragraph"><p>I18n support in Ruby on Rails was introduced in the release 2.2 and is still evolving. The project follows the good Ruby on Rails development tradition of evolving solutions in plugins and real applications first and then cherry-picking the best bread of most widely useful features second for inclusion to the core.</p></div>
+<div class="paragraph"><p>Thus we encourage everybody to experiment with new ideas and features in plugins or other libraries and make them available to the community. (Don’t forget to announce your work on our <a href="http://groups.google.com/group/rails-i18n">mailinglist</a>!)</p></div>
+<div class="paragraph"><p>If you find your own locale (language) missing from our <a href="http://github.com/svenfuchs/rails-i18n/tree/master/rails/locale">example translations data</a> repository for Ruby on Rails</p></div>
+</div>
+<h2 id="_resources">9. Resources</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+<a href="http://rails-i18n.org">rails-i18n.org</a> - Homepage of the rails-i18n project. You can find lots of useful resources on the <a href="http://rails-i18n.org/wiki">wiki</a>.
+</p>
+</li>
+<li>
+<p>
+<a href="http://groups.google.com/group/rails-i18n">rails-i18n Google group</a> - The project’s mailinglist.
+</p>
+</li>
+<li>
+<p>
+<a href="http://github.com/svenfuchs/rails-i18n/tree/master">Github: rails-i18n</a> - Code repository for the rails-i18n project. Most importantly you can find lots of <a href="http://github.com/svenfuchs/rails-i18n/tree/master/rails/locale">example translations</a> for Rails that should work for your application in most cases.
+</p>
+</li>
+<li>
+<p>
+<a href="http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview">Lighthouse: rails-i18n</a> - Issue tracker for the rails-i18n project.
+</p>
+</li>
+<li>
+<p>
+<a href="http://github.com/svenfuchs/i18n/tree/master">Github: i18n</a> - Code repository for the i18n gem.
+</p>
+</li>
+<li>
+<p>
+<a href="http://i18n.lighthouseapp.com/projects/14947-ruby-i18n/overview">Lighthouse: i18n</a> - Issue tracker for the i18n gem.
+</p>
+</li>
+</ul></div>
+</div>
+<h2 id="_authors">10. Authors</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Sven Fuchs[http://www.workingwithrails.com/person/9963-sven-fuchs] (initial author)
+</p>
+</li>
+<li>
+<p>
+Karel Minarik[http://www.workingwithrails.com/person/7476-karel-mina-k]
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>If you found this guide useful please consider recommending its authors on <a href="http://www.workingwithrails.com">workingwithrails</a>.</p></div>
</div>
-<h2 id="_footnotes">8. Footnotes</h2>
+<h2 id="_footnotes">11. Footnotes</h2>
<div class="sectionbody">
<div class="paragraph"><p><a id="1"></a>[1] Or, to quote <a href="http://en.wikipedia.org/wiki/Internationalization_and_localization">Wikipedia</a>: <em>"Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text."</em></p></div>
<div class="paragraph"><p><a id="2"></a>[2] Other backends might allow or require to use other formats, e.g. a GetText backend might allow to read GetText files.</p></div>
<div class="paragraph"><p><a id="3"></a>[3] One of these reasons is that we don’t want to any unnecessary load for applications that do not need any I18n capabilities, so we need to keep the I18n library as simple as possible for English. Another reason is that it is virtually impossible to implement a one-fits-all solution for all problems related to I18n for all existing languages. So a solution that allows us to exchange the entire implementation easily is appropriate anyway. This also makes it much easier to experiment with custom features and extensions.</p></div>
</div>
-<h2 id="_changelog">9. Changelog</h2>
+<h2 id="_changelog">12. Changelog</h2>
<div class="sectionbody">
<div class="paragraph"><p><a href="http://rails.lighthouseapp.com/projects/16213/tickets/23">Lighthouse ticket</a></p></div>
</div>
diff --git a/railties/doc/guides/source/form_helpers.txt b/railties/doc/guides/source/form_helpers.txt index d60ed10a39..f4039070dd 100644 --- a/railties/doc/guides/source/form_helpers.txt +++ b/railties/doc/guides/source/form_helpers.txt @@ -14,8 +14,8 @@ In this guide you will: NOTE: This guide is not intended to be a complete documentation of available form helpers and their arguments. Please visit http://api.rubyonrails.org/[the Rails API documentation] for a complete reference. -Basic forms ------------ +Dealing With Basic Forms +------------------------ The most basic form helper is `form_tag`. @@ -113,9 +113,23 @@ This is a common pitfall when using form helpers, since many of them accept mult WARNING: Do not delimit the second hash without doing so with the first hash, otherwise your method invocation will result in an `expecting tASSOC` syntax error. -Checkboxes, radio buttons and other controls -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Helpers for generating form elements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Rails provides a series of helpers for generating form elements such as checkboxes, text fields, radio buttons and so. These basic helpers, with names ending in _tag such as `text_field_tag`, `check_box_tag` just generate a single `<input>` element. The first parameter to these is always the name of the input. This is the name under which value will appear in the `params` hash in the controller. For example if the form contains + +--------------------------- +<%= text_field_tag(:query) %> +--------------------------- + +then the controller code should use +--------------------------- +params[:query] +--------------------------- +to retrieve the value entered by the user. When naming inputs be aware that Rails uses certain conventions that control whether values appear at the top level of the params hash, inside an array or a nested hash and so on. You can read more about them in the <<parameter_names,parameter names>> section. For details on the precise usage of these helpers, please refer to the http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html[API documentation]. +Checkboxes +^^^^^^^^^^ Checkboxes are form controls that give the user a set of options they can enable or disable: ---------------------------------------------------------------------------- @@ -132,6 +146,10 @@ output: <label for="pet_cat">I own a cat</label> ---------------------------------------------------------------------------- +The second parameter to `check_box_tag` is the value of the input. This is the value that will be submitted by the browser if the checkbox is ticked (i.e. the value that will be present in the params hash). With the above form you would check the value of `params[:pet_dog]` and `params[:pet_cat]` to see which pets the user owns. + +Radio buttons +^^^^^^^^^^^^^ Radio buttons, while similar to checkboxes, are controls that specify a set of options in which they are mutually exclusive (user can only pick one): ---------------------------------------------------------------------------- @@ -148,9 +166,13 @@ output: <label for="age_adult">I'm over 21</label> ---------------------------------------------------------------------------- +As with `check_box_tag` the second parameter to `radio_button_tag` is the value of the input. Because these two radio buttons share the same name (age) the user will only be able to select one and `params[:age]` will contain either `child` or `adult`. + IMPORTANT: Always use labels for each checkbox and radio button. They associate text with a specific option and provide a larger clickable region. -Other form controls worth mentioning are the text area, password input and hidden input: +Other helpers of interest +^^^^^^^^^^^^^^^^^^^^^^^^^ +Other form controls worth mentioning are the text area, password input and hidden input: ---------------------------------------------------------------------------- <%= text_area_tag(:message, "Hi, nice site", :size => "24x6") %> @@ -164,55 +186,20 @@ output: <input id="parent_id" name="parent_id" type="hidden" value="5" /> ---------------------------------------------------------------------------- -Hidden inputs are not shown to the user, but they hold data same as any textual input. Values inside them can be changed with JavaScript. +Hidden inputs are not shown to the user, but they hold data like any textual input. Values inside them can be changed with JavaScript. TIP: If you're using password input fields (for any purpose), you might want to prevent their values showing up in application logs by activating `filter_parameter_logging(:password)` in your ApplicationController. -How do forms with PUT or DELETE methods work? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Rails framework encourages RESTful design of your applications, which means you'll be making a lot of "PUT" and "DELETE" requests (besides "GET" and "POST"). Still, most browsers _don't support_ methods other than "GET" and "POST" when it comes to submitting forms. How does this work, then? - -Rails works around this issue by emulating other methods over POST with a hidden input named `"_method"` that is set to reflect the desired method: - ----------------------------------------------------------------------------- -form_tag(search_path, :method => "put") - -output: - -<form action="/search" method="post"> - <div style="margin:0;padding:0"> - <input name="_method" type="hidden" value="put" /> - <input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" /> - </div> - ... ----------------------------------------------------------------------------- - -When parsing POSTed data, Rails will take into account the special `_method` parameter and act as if the HTTP method was the one specified inside it ("PUT" in this example). -Different Families of helpers ------------------------------- - -Most of Rails' form helpers are available in two forms. - -Barebones helpers -~~~~~~~~~~~~~~~~~~ -These just generate the appropriate markup. These have names ending in _tag such as `text_field_tag`, `check_box_tag`. The first parameter to these is always the name of the input. This is the name under which value will appear in the `params` hash in the controller. For example if the form contains ---------------------------- -<%= text_field_tag(:query) %> ---------------------------- - -then the controller code should use ---------------------------- -params[:query] ---------------------------- -to retrieve the value entered by the user. When naming inputs be aware that Rails uses certain conventions that control whether values appear at the top level of the params hash, inside an array or a nested hash and so on. You can read more about them in the <<parameter_names,parameter names>> section. For details on the precise usage of these helpers, please refer to the http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html[API documentation]. +Dealing With Model Objects +-------------------------- Model object helpers -~~~~~~~~~~~~~~~~~~~~~ -These are designed to work with a model object (commonly an Active Record object but this need not be the case). These lack the _tag suffix, for example `text_field`, `text_area`. +~~~~~~~~~~~~~~~~~~~~~~ -For these helpers the first arguement is the name of an instance variable and the second is the name a method (usually an attribute) to call on that object. Rails will set the value of the input control to the return value of that method for the object and set an appropriate input name. If your controller has defined `@person` and that person's name is Henry then a form containing: +A particularly common task for a form is editing or creating a model object. While the `*_tag` helpers could certainly be used for this task they are somewhat verbose as for each tag you would have to ensure the correct parameter name is used and set the default value of the input appropriately. Rails provides helpers tailored to this task. These helpers lack the _tag suffix, for example `text_field`, `text_area`. + +For these helpers the first argument is the name of an instance variable and the second is the name of a method (usually an attribute) to call on that object. Rails will set the value of the input control to the return value of that method for the object and set an appropriate input name. If your controller has defined `@person` and that person's name is Henry then a form containing: --------------------------- <%= text_field(:person, :name) %> @@ -227,10 +214,15 @@ Upon form submission the value entered by the user will be stored in `params[:pe ============================================================================ You must pass the name of an instance variable, i.e. `:person` or `"person"`, not an actual instance of your model object. ============================================================================ -Forms that deal with model attributes -------------------------------------- -While the helpers seen so far are handy Rails can save you some work. For example typically a form is used to edit multiple attributes of a single object, so having to repeat the name of the object being edited is clumsy. The following examples will handle an Article model. First, have the controller create one: +Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the link:./activerecord_validations_callbacks.html#_using_the_tt_errors_tt_collection_in_your_view_templates[Active Record Validations and Callbacks] guide. + +Binding a form to an object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +While this is an increase in comfort it is far from perfect. If Person has many attributes to edit then we would be repeating the name of the edited object many times. What we want to do is somehow bind a form to a model object which is exactly what `form_for` does. + +Assume we have a controller for dealing with articles: .articles_controller.rb ---------------------------------------------------------------------------- @@ -239,7 +231,7 @@ def new end ---------------------------------------------------------------------------- -Now switch to the view. The first thing to remember is to use the `form_for` helper instead of `form_tag`, and that you should pass the model name and object as arguments: +The corresponding view using `form_for` looks like this .articles/new.html.erb ---------------------------------------------------------------------------- @@ -252,9 +244,9 @@ Now switch to the view. The first thing to remember is to use the `form_for` hel There are a few things to note here: -1. `:article` is the name of the model and `@article` is the record. +1. `:article` is the name of the model and `@article` is the actual object being edited. 2. There is a single hash of options. Routing options are passed inside `:url` hash, HTML options are passed in the `:html` hash. -3. The `form_for` method yields *a form builder* object (the `f` variable). +3. The `form_for` method yields a *form builder* object (the `f` variable). 4. Methods to create form controls are called *on* the form builder object `f` The resulting HTML is: @@ -270,10 +262,30 @@ The name passed to `form_for` controls where in the params hash the form values The helper methods called on the form builder are identical to the model object helpers except that it is not necessary to specify which object is being edited since this is already managed by the form builder. +You can create a similar binding without actually creating `<form>` tags with the `fields_for` helper. This is useful for editing additional model objects with the same form. For example if you had a Person model with an associated ContactDetail model you could create a form for editing both like so: +------------- +<% form_for @person do |person_form| %> + <%= person_form.text_field :name %> + <% fields_for @person.contact_detail do |contact_details_form| %> + <%= contact_details_form.text_field :phone_number %> + <% end %> +<% end %> +------------- + +which produces the following output: + +------------- +<form action="/people/1" class="edit_person" id="edit_person_1" method="post"> + <input id="person_name" name="person[name]" size="30" type="text" /> + <input id="contact_detail_phone_number" name="contact_detail[phone_number]" size="30" type="text" /> +</form> +------------- +The object yielded by `fields_for` is a form builder like the one yielded by `form_for` (in fact `form_for` calls `fields_for` internally). + Relying on record identification ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In the previous chapter you handled the Article model. This model is directly available to users of our application, so -- following the best practices for developing with Rails -- you should declare it *a resource*. +The Article model is directly available to users of our application, so -- following the best practices for developing with Rails -- you should declare it *a resource*. When dealing with RESTful resources, calls to `form_for` can get significantly easier if you rely on *record identification*. In short, you can just pass the model instance and have Rails figure out model name and the rest: @@ -309,15 +321,37 @@ will create a form that submits to the articles controller inside the admin name ------- form_for [:admin, :management, @article] ------- -For more information on Rails' routing system and the associated conventions, please see the link:../routing_outside_in.html[routing guide]. +For more information on Rails' routing system and the associated conventions, please see the link:./routing_outside_in.html[routing guide]. + + +How do forms with PUT or DELETE methods work? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Rails framework encourages RESTful design of your applications, which means you'll be making a lot of "PUT" and "DELETE" requests (besides "GET" and "POST"). Still, most browsers _don't support_ methods other than "GET" and "POST" when it comes to submitting forms. How does this work, then? + +Rails works around this issue by emulating other methods over POST with a hidden input named `"_method"` that is set to reflect the desired method: + +---------------------------------------------------------------------------- +form_tag(search_path, :method => "put") + +output: + +<form action="/search" method="post"> + <div style="margin:0;padding:0"> + <input name="_method" type="hidden" value="put" /> + <input name="authenticity_token" type="hidden" value="f755bb0ed134b76c432144748a6d4b7a7ddf2b71" /> + </div> + ... +---------------------------------------------------------------------------- +When parsing POSTed data, Rails will take into account the special `_method` parameter and act as if the HTTP method was the one specified inside it ("PUT" in this example). Making select boxes with ease ----------------------------- -Select boxes in HTML require a significant amount of markup (one `OPTION` element for each option to choose from), therefore it makes the most sense for them to be dynamically generated from data stored in arrays or hashes. +Select boxes in HTML require a significant amount of markup (one `OPTION` element for each option to choose from), therefore it makes the most sense for them to be dynamically generated. -Here is what our wanted markup might look like: +Here is what the markup might look like: ---------------------------------------------------------------------------- <select name="city_id" id="city_id"> @@ -328,7 +362,7 @@ Here is what our wanted markup might look like: </select> ---------------------------------------------------------------------------- -Here you have a list of cities where their names are presented to the user, but internally the application only wants to handle their IDs so they are used as the options' value attributes. Let's see how Rails can help out here. +Here you have a list of cities whose names are presented to the user. Internally the application only wants to handle their IDs so they are used as the options' value attribute. Let's see how Rails can help out here. The select tag and options ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -452,10 +486,10 @@ To leverage time zone support in Rails, you have to ask our users what time zone There is also `time_zone_options_for_select` helper for a more manual (therefore more customizable) way of doing this. Read the API documentation to learn about the possible arguments for these two methods. -Rails _used_ to have a `country_select` helper for choosing countries but this has been extracted to the http://github.com/rails/country_select/tree/master[country_select plugin]. When using this do be aware that the exclusion or inclusion of certain names from the list can be somewhat controversial (and was the reason this functionality was extracted from rails) +Rails _used_ to have a `country_select` helper for choosing countries but this has been extracted to the http://github.com/rails/country_select/tree/master[country_select plugin]. When using this do be aware that the exclusion or inclusion of certain names from the list can be somewhat controversial (and was the reason this functionality was extracted from rails). -Date and time select boxes --------------------------- +Using Date and Time Form Helpers +-------------------------------- The date and time helpers differ from all the other form helpers in two important respects: @@ -511,63 +545,7 @@ As a rule of thumb you should be using `date_select` when working with model obj NOTE: In many cases the built in date pickers are clumsy as they do not aid the user in working out the relationship between the date and the day of the week. -Form builders -------------- - -As mentioned previously the object yielded by `form_for` and `fields_for` is an instance of FormBuilder (or a subclass thereof). Form builders encapsulate the notion of displaying a form elements for a single object. While you can of course write helpers for your forms in the usual way you can also subclass FormBuilder and add the helpers there. For example - ----------- -<% form_for @person do |f| %> - <%= text_field_with_label f, :first_name %> -<% end %> ----------- -can be replaced with ----------- -<% form_for @person, :builder => LabellingFormBuilder do |f| %> - <%= f.text_field :first_name %> -<% end %> ----------- -by defining a LabellingFormBuilder class similar to the following: - -[source, ruby] -------- -class LabellingFormBuilder < FormBuilder - def text_field attribute, options={} - label(attribute) + text_field(attribute, options) - end -end -------- -If you reuse this frequently you could define a `labeled_form_for` helper that automatically applies the `:builder => LabellingFormBuilder` option. - -The form builder used also determines what happens when you do ------- -<%= render :partial => f %> ------- -If `f` is an instance of FormBuilder then this will render the 'form' partial, setting the partial's object to the form builder. If the form builder is of class LabellingFormBuilder then the 'labelling_form' partial would be rendered instead. - -Scoping out form controls with `fields_for` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -`fields_for` creates a form builder in exactly the same way as `form_for` but doesn't create the actual `<form>` tags. It creates a scope around a specific model object like `form_for`, which is useful for specifying additional model objects in the same form. For example if you had a Person model with an associated ContactDetail model you could create a form for editing both like so: -------------- -<% form_for @person do |person_form| %> - <%= person_form.text_field :name %> - <% fields_for @person.contact_detail do |contact_details_form| %> - <%= contact_details_form.text_field :phone_number %> - <% end %> -<% end %> -------------- - -which produces the following output: - -------------- -<form action="/people/1" class="edit_person" id="edit_person_1" method="post"> - <input id="person_name" name="person[name]" size="30" type="text" /> - <input id="contact_detail_phone_number" name="contact_detail[phone_number]" size="30" type="text" /> -</form> -------------- - -File Uploads +Uploading Files -------------- A common task is uploading some sort of file, whether it's a picture of a person or a CSV file containing data to process. The most important thing to remember with file uploads is that the form's encoding *MUST* be set to multipart/form-data. If you forget to do this the file will not be uploaded. This can be done by passing `:multi_part => true` as an HTML option. This means that in the case of `form_tag` it must be passed in the second options hash and in the case of `form_for` inside the `:html` hash. @@ -605,13 +583,48 @@ Dealing with Ajax ~~~~~~~~~~~~~~~~~ Unlike other forms making an asynchronous file upload form is not as simple as replacing `form_for` with `remote_form_for`. With an AJAX form the serialization is done by javascript running inside the browser and since javascript cannot read files from your hard drive the file cannot be uploaded. The most common workaround is to use an invisible iframe that serves as the target for the form submission. -Parameter Names ---------------- +Customising Form Builders +------------------------- + +As mentioned previously the object yielded by `form_for` and `fields_for` is an instance of FormBuilder (or a subclass thereof). Form builders encapsulate the notion of displaying a form elements for a single object. While you can of course write helpers for your forms in the usual way you can also subclass FormBuilder and add the helpers there. For example + +---------- +<% form_for @person do |f| %> + <%= text_field_with_label f, :first_name %> +<% end %> +---------- +can be replaced with +---------- +<% form_for @person, :builder => LabellingFormBuilder do |f| %> + <%= f.text_field :first_name %> +<% end %> +---------- +by defining a LabellingFormBuilder class similar to the following: + +[source, ruby] +------- +class LabellingFormBuilder < FormBuilder + def text_field attribute, options={} + label(attribute) + text_field(attribute, options) + end +end +------- +If you reuse this frequently you could define a `labeled_form_for` helper that automatically applies the `:builder => LabellingFormBuilder` option. + +The form builder used also determines what happens when you do +------ +<%= render :partial => f %> +------ +If `f` is an instance of FormBuilder then this will render the 'form' partial, setting the partial's object to the form builder. If the form builder is of class LabellingFormBuilder then the 'labelling_form' partial would be rendered instead. + +Understanding Parameter Naming Conventions +----------------------------------------- + [[parameter_names]] -As you've seen in the previous sections values from forms can appear either at the top level of the params hash or may appear nested in another hash. For example in a standard create +As you've seen in the previous sections, values from forms can appear either at the top level of the params hash or may appear nested in another hash. For example in a standard create action for a Person model, `params[:model]` would usually be a hash of all the attributes for the person to create. The params hash can also contain arrays, arrays of hashes and so on. -Fundamentally HTML forms don't know about any sort of structured data. All they know about is name-value pairs. Rails tacks some conventions onto parameter names which it uses to express some structure. +Fundamentally HTML forms don't know about any sort of structured data, all they generate is name-value pairs. The arrays and hashes you see in your application are the result of some parameter naming conventions that Rails uses. [TIP] ======================== @@ -724,8 +737,8 @@ As a shortcut you can append [] to the name and omit the `:index` option. This i -------- produces exactly the same output as the previous example. -Complex forms -------------- +Building Complex forms +---------------------- Many apps grow beyond simple forms editing a single object. For example when creating a Person instance you might want to allow the user to (on the same form) create multiple address records (home, work etc.). When later editing that person the user should be able to add, remove or amend addresses as necessary. While this guide has shown you all the pieces necessary to handle this, Rails does not yet have a standard end-to-end way of accomplishing this, but many have come up with viable approaches. These include: diff --git a/railties/doc/guides/source/i18n.txt b/railties/doc/guides/source/i18n.txt index 25abac7f4c..2638807761 100644 --- a/railties/doc/guides/source/i18n.txt +++ b/railties/doc/guides/source/i18n.txt @@ -12,7 +12,7 @@ Internationalization is a complex problem. Natural languages differ in so many w * providing support for English and similar languages out of the box * making it easy to customize and extend everything for other languages -As part of this solution, *every static string in the Rails framework* -- eg. ActiveRecord validation messages, time and date formats -- *has been internationalized*, so _localization_ of a Rails application means "over-riding" these defaults. +As part of this solution, *every static string in the Rails framework* -- eg. Active Record validation messages, time and date formats -- *has been internationalized*, so _localization_ of a Rails application means "over-riding" these defaults. === The overall architecture of the library @@ -74,7 +74,7 @@ en: hello: "Hello world" ------------------------------------------------------- -This means, that in the +:en+ locale, the key _hello_ will map to _Hello world_ string. Every string inside Rails is internationalized in this way, see for instance ActiveRecord validation messages in the http://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml[+activerecord/lib/active_record/locale/en.yml+] file or time and date formats in the http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml[+activesupport/lib/active_support/locale/en.yml+] file. You can use YAML or standard Ruby Hashes to store translations in the default (Simple) backend. +This means, that in the +:en+ locale, the key _hello_ will map to _Hello world_ string. Every string inside Rails is internationalized in this way, see for instance Active Record validation messages in the http://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml[+activerecord/lib/active_record/locale/en.yml+] file or time and date formats in the http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml[+activesupport/lib/active_support/locale/en.yml+] file. You can use YAML or standard Ruby Hashes to store translations in the default (Simple) backend. The I18n library will use *English* as a *default locale*, ie. if you don't set a different locale, +:en+ will be used for looking up translations. @@ -112,22 +112,115 @@ I18n.default_locale = :pt === Setting and passing the locale -By default the I18n library will use :en (English) as a I18n.default_locale for looking up translations (if you do not specify a locale for a lookup). +If you want to translate your Rails application to a *single language other than English* (the default locale), you can set I18n.default_locale to your locale in +environment.rb+ or an initializer as shown above, and it will persist through the requests. -If you want to translate your Rails application to a single language other than English you can set I18n.default_locale to your locale. If you want to change the locale on a per-request basis though you can set it in a before_filter on the ApplicationController like this: +However, you would probably like to *provide support for more locales* in your application. In such case, you need to set and pass the locale between requests. + +WARNING: You may be tempted to store choosed locale in a _session_ or a _cookie_. *Do not do so*. The locale should be transparent and a part of the URL. This way you don't break people's basic assumptions about the web itself: if you send a URL of some page to a friend, she should see the same page, same content. A fancy word for this would be that you're being http://en.wikipedia.org/wiki/Representational_State_Transfer[_RESTful_]. There may be some exceptions to this rule, which are discussed below. + +The _setting part_ is easy. You can set locale in a +before_filter+ in the ApplicationController like this: [source, ruby] ------------------------------------------------------- before_filter :set_locale def set_locale - # if this is nil then I18n.default_locale will be used + # if params[:locale] is nil then I18n.default_locale will be used I18n.locale = params[:locale] end ------------------------------------------------------- -This will already work for URLs where you pass the locale as a query parameter as in example.com?locale=pt (which is what Google also does). +This requires you to pass the locale as a URL query parameter as in +http://example.com/books?locale=pt+. (This is eg. Google's approach). So +http://localhost:3000?locale=pt+ will load the Portugese localization, whereas +http://localhost:3000?locale=de+ would load the German localization, and so on. + +Of course, you probably don't want to manually include locale in every URL all over your application, or want the URLs look differently, eg. the usual +http://example.com/pt/books+ versus +http://example.com/en/books+. Let's discuss the different options you have. + +IMPORTANT: Following examples rely on having locales loaded into your application available as an array of strings like +["en", "es", "gr"]+. This is not inclued in current version of Rails 2.2 -- forthcoming Rails version 2.3 will contain easy accesor +available_locales+. (See http://github.com/svenfuchs/i18n/commit/411f8fe7[this commit] and background at http://rails-i18n.org/wiki/pages/i18n-available_locales[Rails I18n Wiki].) + +We have to include support for getting available locales manually in an initializer like this: + +[source, ruby] +------------------------------------------------------- +# config/initializers/available_locales.rb +# +# Get loaded locales conveniently +# See http://rails-i18n.org/wiki/pages/i18n-available_locales +module I18n + class << self + def available_locales; backend.available_locales; end + end + module Backend + class Simple + def available_locales; translations.keys.collect { |l| l.to_s }.sort; end + end + end +end + +# You need to "force-initialize" loaded locales +I18n.backend.send(:init_translations) + +AVAILABLE_LOCALES = I18n.backend.available_locales +RAILS_DEFAULT_LOGGER.debug "* Loaded locales: #{AVAILABLE_LOCALES.inspect}" +------------------------------------------------------- + +You can then wrap the constant for easy access in ApplicationController: + +[source, ruby] +------------------------------------------------------- +class ApplicationController < ActionController::Base + def available_locales; AVAILABLE_LOCALES; end +end +------------------------------------------------------- + +=== Setting locale from the domain name -TIP: For other URL designs, see http://rails-i18n.org/wiki/pages/how-to-encode-the-current-locale-in-the-url[How to encode the current locale in the URL]. +One option you have is to set the locale from the domain name, where your application runs. For example, we want +www.example.com+ to load English (or default) locale, and +www.example.es+ to load Spanish locale. Thus the _top-level domain name_ is used for locale setting. This has several advantages: + +* Locale is an _obvious_ part of the URL +* People intuitively grasp in which language the content will be displayed +* It is very trivial to implement in Rails +* Search engines seem to like that content in different languages lives at different, inter-linked domains + +You can implement it like this in your ApplicationController: + +[source, ruby] +------------------------------------------------------- +before_filter :set_locale +def set_locale + I18n.locale = extract_locale_from_uri +end +# Get locale from top-level domain or return nil if such locale is not available +# You have to put something like: +# 127.0.0.1 application.com +# 127.0.0.1 application.it +# 127.0.0.1 application.pl +# in your /etc/hosts file to try this out locally +def extract_locale_from_tld + parsed_locale = request.host.split('.').last + (available_locales.include? parsed_locale) ? parsed_locale : nil +end +------------------------------------------------------- + +We can also set the locale from the _subdomain_ in very similar way: + +[source, ruby] +------------------------------------------------------- +# Get locale code from request subdomain (like http://it.application.local:3000) +# You have to put something like: +# 127.0.0.1 gr.application.local +# in your /etc/hosts file to try this out locally +def extract_locale_from_subdomain + parsed_locale = request.subdomains.first + (available_locales.include? parsed_locale) ? parsed_locale : nil +end +------------------------------------------------------- + +=== Setting locale from the URL params + +* TODO : Based on *+default_url options+*, http://github.com/karmi/test_default_url_options/blob/master/app/controllers/application.rb#L22-26 + +* TODO : Discussion of plugins (translate_routes and routing_filter) + + +TIP: For setting locale from URL see http://rails-i18n.org/wiki/pages/how-to-encode-the-current-locale-in-the-url[How to encode the current locale in the URL] in the Rails i18n Wiki. Now you've initialized I18n support for your application and told it which locale should be used. With that in place you're now ready for the really interesting stuff. @@ -199,7 +292,7 @@ pirate: There you go. Because you haven't changed the default_locale I18n will use English. Your application now shows: -image:images/i18n/demo_translated_english.png[rails i18n demo translated to english] +image:images/i18n/demo_translated_en.png[rails i18n demo translated to english] And when you change the URL to pass the pirate locale you get: @@ -265,7 +358,7 @@ translate also takes a :scope option which can contain one or many additional ke I18n.t :invalid, :scope => [:active_record, :error_messages] ------------------------------------------------------- -This looks up the :invalid message in the ActiveRecord error messages. +This looks up the :invalid message in the Active Record error messages. Additionally, both the key and scopes can be specified as dot separated keys as in: @@ -314,7 +407,7 @@ I18n.t [:odd, :even], :scope => 'active_record.error_messages' # => ["must be odd", "must be even"] ------------------------------------------------------- -Also, a key can translate to a (potentially nested) hash as grouped translations. E.g. one can receive all ActiveRecord error messages as a Hash with: +Also, a key can translate to a (potentially nested) hash as grouped translations. E.g. one can receive all Active Record error messages as a Hash with: [source, ruby] ------------------------------------------------------- @@ -445,7 +538,7 @@ I18n.t :short, :scope => [:date, :formats] Generally we recommend using YAML as a format for storing translations. There are cases though where you want to store Ruby lambdas as part of your locale data, e.g. for special date -=== Translations for ActiveRecord models +=== Translations for Active Record models You can use the methods Model.human_name and Model.human_attribute_name(attribute) to transparently lookup translations for your model and attribute names. @@ -467,7 +560,7 @@ Then User.human_name will return "Dude" and User.human_attribute_name(:login) wi ==== Error message scopes -ActiveRecord validation error messages can also be translated easily. ActiveRecord gives you a couple of namespaces where you can place your message translations in order to provide different messages and translation for certain models, attributes and/or validations. It also transparently takes single table inheritance into account. +Active Record validation error messages can also be translated easily. Active Record gives you a couple of namespaces where you can place your message translations in order to provide different messages and translation for certain models, attributes and/or validations. It also transparently takes single table inheritance into account. This gives you quite powerful means to flexibly adjust your messages to your application's needs. @@ -480,7 +573,7 @@ class User < ActiveRecord::Base end ------------------------------------------------------- -The key for the error message in this case is :blank. ActiveRecord will lookup this key in the namespaces: +The key for the error message in this case is :blank. Active Record will lookup this key in the namespaces: [source, ruby] ------------------------------------------------------- @@ -509,7 +602,7 @@ class Admin < User end ------------------------------------------------------- -Then ActiveRecord will look for messages in this order: +Then Active Record will look for messages in this order: [source, ruby] ------------------------------------------------------- @@ -556,9 +649,9 @@ count, where available, can be used for pluralization if present: |===================================================================================================== -==== Translations for the ActiveRecord error_messages_for helper +==== Translations for the Active Record error_messages_for helper -If you are using the ActiveRecord error_messages_for helper you will want to add translations for it. +If you are using the Active Record error_messages_for helper you will want to add translations for it. Rails ships with the following translations: @@ -575,11 +668,29 @@ en: ------------------------------------------------------- -=== Other translations and localizations +=== Overview of other built-in methods that provide I18n support + +Rails uses fixed strings and other localizations, such as format strings and other format information in a couple of helpers. Here's a brief overview. + +==== ActionView helper methods + +* distance_of_time_in_words translates and pluralizes its result and interpolates the number of seconds, minutes, hours and so on. See http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L51[datetime.distance_in_words] translations. + +* datetime_select and select_month use translated month names for populating the resulting select tag. See http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L15[date.month_names] for translations. datetime_select also looks up the order option from http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L18[date.order] (unless you pass the option explicitely). All date select helpers translate the prompt using the translations in the http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L83[datetime.prompts] scope if applicable. + +* The number_to_currency, number_with_precision, number_to_percentage, number_with_delimiter and humber_to_human_size helpers use the number format settings located in the http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L2[number] scope. + +==== Active Record methods + +* human_name and human_attribute_name use translations for model names and attribute names if available in the http://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml#L43[activerecord.models] scope. They also support translations for inherited class names (e.g. for use with STI) as explained above in "Error message scopes". + +* ActiveRecord::Errors#generate_message (which is used by Active Record validations but may also be used manually) uses human_name and human_attribute_name (see above). It also translates the error message and supports translations for inherited class names as explained above in "Error message scopes". -Rails uses fixed strings and other localizations, such as format strings and other format information in a couple of helpers. +* ActiveRecord::Errors#full_messages prepends the attribute name to the error message using a separator that will be looked up from http://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L91[activerecord.errors.format.separator] (and defaults to ' '). -TODO list helpers and available keys +==== ActiveSupport methods + +* Array#to_sentence uses format settings as given in the http://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L30[support.array] scope. == Customize your I18n setup @@ -638,8 +749,39 @@ I18n.t :foo, :raise => true # always re-raises exceptions from the backend ------------------------------------------------------- +== Conclusion + +At this point you hopefully have a good overview about how I18n support in Ruby on Rails works and are ready to start translating your project. + +If you find anything missing or wrong in this guide please file a ticket on http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview[our issue tracker]. If you want to discuss certain portions or have questions please sign up to our http://groups.google.com/group/rails-i18n[mailinglist]. + + +== Contributing to Rails I18n + +I18n support in Ruby on Rails was introduced in the release 2.2 and is still evolving. The project follows the good Ruby on Rails development tradition of evolving solutions in plugins and real applications first and then cherry-picking the best bread of most widely useful features second for inclusion to the core. + +Thus we encourage everybody to experiment with new ideas and features in plugins or other libraries and make them available to the community. (Don't forget to announce your work on our http://groups.google.com/group/rails-i18n[mailinglist]!) + +If you find your own locale (language) missing from our http://github.com/svenfuchs/rails-i18n/tree/master/rails/locale[example translations data] repository for Ruby on Rails + + == Resources +* http://rails-i18n.org[rails-i18n.org] - Homepage of the rails-i18n project. You can find lots of useful resources on the http://rails-i18n.org/wiki[wiki]. +* http://groups.google.com/group/rails-i18n[rails-i18n Google group] - The project's mailinglist. +* http://github.com/svenfuchs/rails-i18n/tree/master[Github: rails-i18n] - Code repository for the rails-i18n project. Most importantly you can find lots of http://github.com/svenfuchs/rails-i18n/tree/master/rails/locale[example translations] for Rails that should work for your application in most cases. +* http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview[Lighthouse: rails-i18n] - Issue tracker for the rails-i18n project. +* http://github.com/svenfuchs/i18n/tree/master[Github: i18n] - Code repository for the i18n gem. +* http://i18n.lighthouseapp.com/projects/14947-ruby-i18n/overview[Lighthouse: i18n] - Issue tracker for the i18n gem. + + +== Authors + +* Sven Fuchs[http://www.workingwithrails.com/person/9963-sven-fuchs] (initial author) +* Karel Minarik[http://www.workingwithrails.com/person/7476-karel-mina-k] + +If you found this guide useful please consider recommending its authors on http://www.workingwithrails.com[workingwithrails]. + == Footnotes @@ -649,6 +791,7 @@ I18n.t :foo, :raise => true # always re-raises exceptions from the backend [[[3]]] One of these reasons is that we don't want to any unnecessary load for applications that do not need any I18n capabilities, so we need to keep the I18n library as simple as possible for English. Another reason is that it is virtually impossible to implement a one-fits-all solution for all problems related to I18n for all existing languages. So a solution that allows us to exchange the entire implementation easily is appropriate anyway. This also makes it much easier to experiment with custom features and extensions. + == Changelog == http://rails.lighthouseapp.com/projects/16213/tickets/23[Lighthouse ticket] |