Rails Form helpers
Rails Form helpers
Forms in web applications are an essential interface for user input. However, form markup can quickly become tedious to write and maintain because of form control naming and their numerous attributes. Rails deals away with these complexities by providing view helpers for generating form markup. However, since they have different use-cases, developers are required to know all the differences between similar helper methods before putting them to use.
Forms在web应用程序中是一个必不可少的提供用户输入的interface(接口)。然而,形式标记的编写和维护很快就变得十分乏味是因为表单控件的命名和它们的许多属性。Rails处理这些复杂的(事物)通过提供view helpers来创建form markup。然而,自从有了不同的用户需求,开发人员需要知道所有的similar helper 方法间的的不同在使用它们之前。
In this guide you will:在这个guide中你可以了解到:
- Create search forms and similar kind of generic forms not representing any specific model in your application在你的应用程序中,创建search forms和生成类似的forms它们不代表任何指定的model
- Make model-centric forms for creation and editing of specific database records制造model-centric forms来创建和编辑指定的数据库记录
- Generate select boxes from multiple types of data 从多种数据生成select boxes
- Understand the date and time helpers Rails provides 明白Rails提供的date和time helpers
- Learn what makes a file upload form different 学习什么使得一个文件upload form变得不同
- Learn some cases of building forms to external resources 学习某些情况下为external resources(外部资源)构建forms
- Find out where to look for complex forms 找出在哪里查找复杂的forms
This guide is not intended to be a complete documentation of available form helpers and their arguments. Please visit theRailsAPIdocumentation for a complete reference.
本教程不大算成为一个包含可用的form helpers和它们的参数的完整的文档。请访问theRailsAPIdocumentation得到完整的参考。
1 Dealing with Basic Forms
The most basic form helper is form_tag.最基本的form helper是form_tag。
<%= form_tag do %>
Form contents
<% end %>
When called without arguments like this, it creates a <form> tag which, when submitted, will POST to the current page. For instance, assuming the current page is /home/index, the generated HTML will look like this (some line breaks added for readability):
当像这样无参调用时,它创建一个<form>标签,当提交这个表单时,会提交到当前页面。作为实例,假设当前页面是/home/index,创建的HTML将会像这样(有一些换行为了增加可读性):
<form accept-charset=“UTF-8” action=“/home/index” method=“post”>
<div style=“margin:0;padding:0”>
<input name=“utf8” type=“hidden” value=“✓” />
<input name=“authenticity_token” type=“hidden” value=“f755bb0ed134b76c432144748a6d4b7a7ddf2b71” />
</div>
Form contents
</form>
Now, you’ll notice that the HTML contains something extra: a div element with two hidden input elements inside. This div is important, because the form cannot be successfully submitted without it. The first input element with name utf8 enforces browsers to properly respect your form’s character encoding and is generated for all forms whether their actions are “GET” or “POST”. The second input element with name authenticity_token is a security feature of Rails called cross-site request forgery protection, and form helpers generate it for every non-GET form (provided that this security feature is enabled). You can read more about this in the SecurityGuide.
现在,你将会注意到HTML包含一些额外的东西:一个div元素和在里边的两个隐藏的input元素。这个div很重要,因为如果没有它form不能够成功的被提交。第一个input元素有name utf8会强制浏览器合适的遵循你的form’s的字符编码并且无论是它创建的所有forms还是它们的actions(“GET” or “POST”)。第二个input元素使用name authenticity_token它是一个Rails的安全特性调用cross-site request forgery protection(站间请求保护),并且form helpers为每个non-GET form (确保这个安全特性是有效的) 创建它。你可以阅读关于他的更多信息在SecurityGuide中。
Throughout this guide, the div with the hidden input elements will be excluded排除from code samples for brevity短暂.通过这个教程,div里面的两个隐藏的input元素将会从samples code暂时排除。
1.1 A Generic Search Form通用搜索表单
One of the most basic forms you see on the web is a search form. This form contains:
搜索表单是你在web上最常见的基本表单之一。这个表单包含:
- a form element with “GET” method,
- a label for the input,
- a text input element, and
- a submit element.
To create this form you will use form_tag, label_tag, text_field_tag, and submit_tag, respectively. Like this:
要创建这个表单你将会分别使用form_tag,label_tag,text_field_tag,and submit_tag。
<%= form_tag(“/search”, :method => “get”) do %>
<%= label_tag(:q, “Search for:”) %>
<%= text_field_tag(:q) %>
<%= submit_tag(“Search”) %>
<% end %>
This will generate the following HTML:这将会生成随后的HTML:
<form accept-charset=“UTF-8” action=“/search” method=“get”>
<label for=“q”>Search for:</label>
<input id=“q” name=“q” type=“text” />#label 和input的for和id的值的统一是为了将它们关联起来选中label则input则被激活
<input name=“commit” type=“submit” value=“Search” />
</form>
For every form input, an ID attribute is generated from its name (“q” in the example). These IDs can be very useful for CSS styling or manipulation of form controls with JavaScript.
对于每个form input,ID属性被从它的name生成(本例中是q)。这些IDs在CSS styling中非常有用或者使用JavaScript操作form controls。
Besides text_field_tag and submit_tag, there is a similar helper for every form control in HTML.下面的text_field_tag and submit_tag,它们是每个form control在HTML中的similar helper。
Always use “GET” as the method for search forms. This allows users to bookmark a specific search and get back to it. More generally Rails encourages you to use the right HTTP verb for an action.
通常对search forms使用“GET”方法。这允许用户将一个指定的搜索(的url添加)书签并(通过这个书签)取回查询结果。更常规的方法Rails鼓励你对于一个HTTP 动作使用正确的verb(动词)。
1.2 Multiple Hashes in Form Helper Calls
The form_tag helper accepts 2 arguments: the path for the action and an options hash. This hash specifies the method of form submission and HTML options such as the form element’s class.
form_tag helper接收两个参数:path的值为动作的路径以及一个options的hash字典。
这个hash字典指定提交form的方法和(一些)HTML选项如form元素的class属性。
As with the link_to helper, the path argument doesn’t have to be given a string; it can be a hash of URL parameters recognizable by Rails’ routing mechanism, which will turn the hash into a valid URL. However, since both arguments to form_tag are hashes, you can easily run into a problem if you would like to specify both. For instance, let’s say you write this:
如同link_to helper,path参数不是必须是被提供给一个string;它可以是被Rails的routing mechanism组织的一个URL参数的hash字典,他将转接hash(键)到一个有效的URL。然而,
既然两个参数form_tag都是hash字典形式,你可以容易的陷入一个问题如果你想指定他们两个。下面的实例,让告诉你写下如下代码:
form_tag(:controller => “people”, :action => “search”, :method => “get”, :class => “nifty_form”)
=> ‘<form accept-charset=“UTF-8” action=“/people/search?method=get&class=nifty_form” method=“post”>’
Here, method and class are appended to the query string of the generated URL because you even though you mean to write two hashes, you really only specified one. So you need to tell Ruby which is which by delimiting the first hash (or both) with curly brackets. This will generate the HTML you expect:
这里,method和class被添加到生成的UIR的query字符串中是因为即使你曾经意图写的两个hash字段,你实际上只指定了一个。因此你需要告诉Ruby其中的那一个被限制为第一个hash(或者两个都)使用大括号。这是生成的HTML你期望的:
form_tag({:controller => “people”, :action => “search”}, :method => “get”, :class => “nifty_form”)
=> ‘<form accept-charset=“UTF-8” action=“/people/search” method=“get”>’
1.3 Helpers for Generating Form Elements
Rails provides a series of helpers for generating form elements such as checkboxes, text fields, and radio buttons. These basic helpers, with names ending in “_tag” (such as text_field_tag and check_box_tag), generate just a single <input> element. The first parameter to these is always the name of the input. When the form is submitted, the name will be passed along with the form data, and will make its way to the params hash in the controller with the value entered by the user for that field. For example, if the form contains <%= text_field_tag(:query) %>, then you would be able to get the value of this field in the controller with params[:query].
Rails提供一系列的helpers来创建form元素例如checkboxes,text fields以及radio buttons。这些基本的helpers,使用“_tag”结尾(例如text_field_tag and check_box_tag),创建一个单独的<input>元素。其第一个参数通常是input的name。当这个form被提交的时候,名称也将会和form data一起(提交),并且将会以它的方式将它和用户输入到field中的值传递到controller中的params hash中。例如,如果form包含<%= text_field_tag(:query) %>,然后你可以在controller使用params[:query]获取这个field中的值。
When naming inputs, Rails uses certain conventions that make it possible to submit parameters with non-scalar values such as arrays or hashes, which will also be accessible in params. You can read more about them in chapter7ofthisguide. For details on the precise usage of these helpers, please refer to the APIdocumentation.
当命名了inputs,Rails使用某些公约使得提交parameters和non-scalar(非标量)的值例如arrays或者hashes成为了可能,其也可以通过使用params来访问。你可以阅读chapter7ofthisguide来了解更多的信息。要知道这些helpers的精确用法的描述,请参阅APIdocumentation。
1.3.1 Checkboxes复选框
Checkboxes are form controls that give the user a set of options they can enable or disable:
Checkboxes是form控件它提供给用户一个设置选项这个选项可以选中和取消选中:
<%= check_box_tag(:pet_dog) %>
<%= label_tag(:pet_dog, “I own a dog”) %>
<%= check_box_tag(:pet_cat) %>
<%= label_tag(:pet_cat, “I own a cat”) %>
This generates the following:这将生成随后的代码:
<input id=“pet_dog” name=“pet_dog” type=“checkbox” value=“1” />
<label for=“pet_dog”>I own a dog</label>
<input id=“pet_cat” name=“pet_cat” type=“checkbox” value=“1” />
<label for=“pet_cat”>I own a cat</label>
The first parameter to check_box_tag, of course, is the name of the input. The second parameter, naturally, is the value of the input. This value will be included in the form data (and be present in params) when the checkbox is checked.
check_box_tag的第一个参数,当然是input的name。第二个参数,自然地,是input输入的值。这个value将会包含在form data中(并且使用params表示)当checkbox被选中。
1.3.2 Radio Buttons单选按钮
Radio buttons, while similar to checkboxes, are controls that specify a set of options in which they are mutually exclusive (i.e., the user can only pick one):
单选框,它和复选框很类似,它是一种控件指定一些设置选项这些选项之间是相互排斥的(i.e., 用户仅仅只能选择一个):
<%= radio_button_tag(:age, “child”) %>
<%= label_tag(:age_child, “I am younger than 21”) %>
<%= radio_button_tag(:age, “adult”) %>
<%= label_tag(:age_adult, “I’m over 21”) %>
Output:输出:
<input id=“age_child” name=“age” type=“radio” value=“child” />
<label for=“age_child”>I am younger than 21</label>
<input id=“age_adult” name=“age” type=“radio” value=“adult” />
<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”.
正如check_box_tag,radio_button_tag的第二个参数是input的value。因为这两个radio buttons分享相同的name(age)用户仅仅能够选择一个,并且params[:age]将会包含或者“child”或者“adult”。
Always use labels for checkbox and radio buttons. They associate text with a specific option and make it easier for users to click the inputs by expanding扩大the clickable region.
经常把checkbox或radio button和labels标签一起使用。他们将文字text和一个特定的选项管理起来并且通过扩大可点击区域使得用户能够更加容易点击。
1.4 Other Helpers of Interest其他有趣的Helpers
Other form controls worth mentioning are textareas, password fields, hidden fields, search fields, telephone fields, URL fields and email fields:
其他值得一提的form控件是textareas,password,fields,hidden fields,search fields,telephone fields,URL fields和email fields:
other helpers of interest<br />
<%= label_tag(:message, “content”) %>
<%= text_area_tag(:message, “Hi, nice site”, :size => “24x6”) %><br />
<%= label_tag(:password, “password”) %>
<%= password_field_tag(:password) %><br />
<%= hidden_field_tag(:parent_id, “5”) %><br />
<%= label_tag(:user_name, “search:”) %>
<%= search_field(:user, :name) %><br />
<%= label_tag(:user_phone, “phone”) %>
<%= telephone_field(:user, :phone) %><br />
<%= label_tag(:user_homepage, “homepage”) %>
<%= url_field(:user, :homepage) %><br />
<%= label_tag(:user_address, “address”) %>
<%= email_field(:user, :address) %><br />
Output:输出:
<label for=“message”>content</label>
<textarea cols=“24” id=“message” name=“message” rows=“6”>Hi, nice site</textarea><br />
<label for=“password”>password</label>
<input id=“password” name=“password” type=“password” /><br />
<input id=“parent_id” name=“parent_id” type=“hidden” value=“5” /><br />
<label for=“user_name”>search:</label>
<input id=“user_name” name=“user[name]” size=“30” type=“search” /><br />
<label for=“user_phone”>phone</label>
<input id=“user_phone” name=“user[phone]” size=“30” type=“tel” /><br />
<label for=“user_homepage”>homepage</label>
<input id=“user_homepage” name=“user[homepage]” size=“30” type=“url” /><br />
<label for=“user_address”>address</label>
<input id=“user_address” name=“user[address]” size=“30” type=“email” /><br /
Hidden inputs are not shown to the user but instead hold data like any textual input. Values inside them can be changed with JavaScript.
Hidden inputs不显示给用户但是它可以hold任何文本形式数据的输入。Hidden里面的值可以用JavaScript改变。
The search, telephone, URL, and email inputs are HTML5 controls. If you require your app to have a consistent experience in older browsers, you will need an HTML5 polyfill (provided by CSS and/or JavaScript). There is definitely noshortageofsolutionsforthis, although a couple of popular tools at the moment are Modernizr and yepnope, which provide a simple way to add functionality based on the presence of detected HTML5 features.
search, telephone, URL, 和email inputs是HTML5控件。如果你需要你的app在旧的浏览器上面拥有兼容的体验,你将需要一个HTML5 polyfill(provided by CSS and/or JavaScript)。这里肯定noshortageofsolutionsforthis(没有针对此类问题一致的解决方法),即使现在有了一组广受欢迎的工具是Modernizr and yepnope,他们提供了一个简单的方法来添加检测HTML5特性功能是否存在。
If you’re using password input fields (for any purpose), you might want to configure your application to prevent those parameters from being logged. You can learn about this in the SecurityGuide.
如果你正在使用password input fields(无论何种原因),你可能想配置你的应用程序以防止记录这些参数。你可以从SecurityGuide中了解这些信息。
2 Dealing with Model Objects
2.1 Model Object Helpers
A particularly common task for a form is editing or creating a model object. While the *tag helpers can 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.
form的一个格外普遍的任务是编辑或创建一个model对象。然而,无疑*tag helpers能够在这个任务中使用,他们有点繁琐,为每一个标签,你就必须确保使用中的参数名称的正确使用,并设置适当的输入的默认值。Rails为这个任务量身定制了helpers。这些helpers缺少tag 后缀,例如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:
对于这些helpers第一个参数是实例变量的name,第二个是方法的名称(通常是一个属性)来调用那个对象。Rails将(传输)input 控件的值给该对象的方法的返回值,并设置一个适当的输入名称。如果你的控件name已经被定义为@person并且person’s name is Henry那么这个form包含:
<%= text_field(:person, :name) %>
will produce output similar to
<input id=“person_name” name=“person[name]” type=“text” value=“Henry”/>
Upon form submission the value entered by the user will be stored in params[:person][:name]. The params[:person] hash is suitable for passing to Person.new or, if @person is an instance of Person, @person.update_attributes. While the name of an attribute is the most common second parameter to these helpers this is not compulsory. In the example above, as long as person objects have a name and a name= method Rails will be happy.
在用户输入后,并由form提交的值将会被存储在params[:person][:name]中。params[:person]相当于Person.new,如果@person是一个Person的实例,则相当于@person.update_attributes。虽然这些helpers的属性名称最常见的是第二个参数,但这不是强制性的。在例子中,只要Person对象有一个名称和一个name=method那么Rails会很乐意。
You must pass the name of an instance variable, i.e. :person or “person”, not an actual instance of your model object.你必须提供一个实例变量的名称,i.e. :person or “person”,不是一个你model对象中实际的实例。
Rails provides helpers for displaying the validation errors associated with a model object. These are covered in detail by the ActiveRecordValidationsandCallbacks guide.
2.2 Binding a Form to an Object将form和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.
虽然添加的这些功能让我们(在使用中)感到舒适但离完美远远不够。如果Person拥有多个属性需要编辑然后我们将会重复被编辑object的name很多次。我们想要(Rails)做的是以某种方式将model object和form绑定,这也恰好是form_for要做的。
Assume we have a controller for dealing with articles app/controllers/articles_controller.rb:
假设我们有一个controller(app/controllers/articles_controller.rb)来处理articles:
def new
@article = Article.new
end
The corresponding view app/views/articles/new.html.erb using form_for looks like this:
<%= form_for @article, :url => { :action => “create” }, :html => {:class => “nifty_form”} do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body, :size => “60x12” %>
<%= f.submit “Create” %>
<% end %>
There are a few things to note here:这里对其做的事情备注如下:
- @article is the actual object being edited. @article是实际上被编辑的object
- There is a single hash of options. Routing options are passed in the :url hash, HTML options are passed in the :html hash. 这里是一个单个hash字典的选项。Routing选项通过:url hash键对提供,HTML选项通过:html hash键对提供
- The form_for method yields a form builder object (the f variable).
- Methods to create form controls are called on the form builder object f创建form控件的方法是通过调用object f的form builder
The resulting HTML is:
<form accept-charset=“UTF-8” action=“/articles/create” method=“post” class=“nifty_form”>
<input id=“article_title” name=“article[title]” size=“30” type=“text” />
<textarea id=“article_body” name=“article[body]” cols=“60” rows=“12”></textarea>
<input name=“commit” type=“submit” value=“Create” />
</form>
The name passed to form_for controls the key used in params to access the form’s values. Here the name is article and so all the inputs have names of the form article[attribute_name]. Accordingly, in the create action params[:article] will be a hash with keys :title and :body. You can read more about the significance of input names in the parameter_names section.
通过form_for控件的name以及parmas使用的关键字来接收form的值。这里的name是article并且form所有的inputs的name都是article[attribute_name]。因此,在create action中params[:article]将会有关键字:title and :body的hash键值。你可以阅读更多的input name的含义在parameter_names章节。
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.
这个调用form builder的helper方法除了不需要指定那个object被编辑既然这已经交给form builder管理,其他部分与model object helpers一致。
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 creating both like so:
你可以创建一个类似的tags组合却没有真正的使用fields_for helper创建<form> tags。这在使用相同的form编辑额外的对象的时候非常有用。例如如果你有一个Person model以及相关联的ContactDetail model你可以创建一个form来创建他们两个如下:
<%= form_for @person, :url => { :action => “create” } 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 accept-charset=“UTF-8” action=“/people/create” id=“new_person” 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(在内部调用fields_for)).
2.3 Relying on Record Identification依托于记录的识别
The Article model is directly available to users of the application, so — following the best practices for developing with Rails — you should declare it a resource:
Article模型是应用程序用户直接可用的,因此——遵循Rails开发最好的实践——你应该声明它为一个resource:
resources :articles
Declaring a resource has a number of side-effects(官网上是side-affects错别字?). See RailsRoutingFromtheOutsideIn for more information on setting up and using resources.
声明一个resource会有一系列的副作用。查看RailsRoutingFromtheOutsideIn来获取在设定和使用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:
当在处理RESTful resources的时候,调用form_for会明显简单的多如果你rely on record identification。简而言之,你可以仅仅通过model实例和Rails来figure out(谋取)model name或者重设它:
## Creating a new article
# long-style:
form_for(@article, :url => articles_path)
# same thing, short-style (record identification gets used):
form_for(@article)
## Editing an existing article
# long-style:
form_for(@article, :url => article_path(@article), :html => { :method => “put” })
# short-style:
form_for(@article)
Notice how the short-style form_for invocation is conveniently the same, regardless of the record being new or existing. Record identification is smart enough to figure out if the record is new by asking record.new_record?. It also selects the correct path to submit to and the name based on the class of the object.
注意short-style的form_for的调用相对如此的方便,无论这个记录是刚开始还是已经存在了。Record identification能够智能识别如果记录是否是new通过询问record.new_record?。它也选择正确的提交路径并且它的name基于object的class。
Rails will also automatically set the class and id of the form appropriately: a form creating an article would have id and class new_article. If you were editing the article with id 23, the class would be set to edit_article and the id to edit_article_23. These attributes will be omitted省略for brevity in the rest of this guide.
Rails也会适当的自动的设置form(元素)的class和id:一个(用于)创建一个article的fom将会拥有id和classnew_article。如果你在正编辑id为23的article,它的class属性将会被设置为edit_article并且id为edit_article_23。为了教程的简洁,这些属性将会被部分忽略。
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, :url, and :method explicitly.
当你正在你的model中使用STI(single-table inheritance),你不能在一个子类中使用 rely on record identification除非他的父类被声明为一个resource。(那么)你将不得不准确的指定model name,:url,:method。
2.3.1 Dealing with Namespaces使用名称空间处理(业务)
If you have created namespaced routes, form_for has a nifty shorthand for that too. If your application has an admin namespace then
如果你已经创建一个namespaced routes,form_for拥有一个可爱的快捷操作来做这些。如果你的应用程序拥有一个admin namespace然后
form_for [:admin, @article]
will create a form that submits to the articles controller inside the admin namespace (submitting to admin_article_path(@article) in the case of an update). If you have several levels of namespacing then the syntax is similar:
将会创建一个form它会提交(信息)到在admin namespace(比如在update情况下会提交到admin_article_path(@article))中的articles controller。如果你有一系列等级的name spacing然后将会有语法智能(处理他们):
form_for [:admin, :management, @article]
For more information on Rails’ routing system and the associated conventions, please see the routingguide.
得到更多的关于Rails的routing和关联约定,请阅读routingguide。
2.4 How do forms with PUT or DELETE methods work?表单的PUT或者DELETE方法是如何工作的
The 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”). However, most browsers don’t support methods other than “GET” and “POST” when it comes to submitting forms.
Rails框架鼓励在你的应用程序中使用RESTful风格设计,意思是你将会产生许多“PUT”和“DELETE”请求(在“GET”AND“POST”之后)。然而,大多数的浏览器在提交表单的时候并不支持超过”GET”AND”POST”之外的方法。
Rails works around this issue by emulating模拟other methods over POST with a hidden input named “_method”, which is set to reflect the desired method:
Rails围绕这个问题通过在POST之外添加一个隐藏的(命名为“_method”)input标签来模拟其他的方法,这个input标签被用来呈现所需的方法:
form_tag(search_path, :method => “put”)
output:
<form accept-charset=“UTF-8” action=“/search” method=“post”>
<div style=“margin:0;padding:0”>
<input name=“_method” type=“hidden” value=“put” />
<input name=“utf8” type=“hidden” value=“✓” />
<input name=“authenticity_token” type=“hidden” value=“f755bb0ed134b76c432144748a6d4b7a7ddf2b71” />
</div>
…
When parsing POSTed data, Rails will take into account the special _method parameter and acts as if the HTTP method was the one specified inside it (“PUT” in this example).
当解析POSTed数据的时候,Rails将会出进入指定的_method参数并且如果有一个HTTP方法在里面被指定了(本例中是”PUT”)。
3 Making Select Boxes with Ease使用容易(的方式)来生成Select Boxes
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.
Select boxes在HTML需要标明markup的数量(一个OPTION元素对应需要选择的每一个选项),因此对于他们的动态生成这是有意义的。
Here is what the markup might look like:这里是markup可能的样子:
<select name=“city_id” id=“city_id”>
<option value=“1”>Lisbon</option>
<option value=“2”>Madrid</option>
…
<option value=“12”>Berlin</option>
</select>
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.
这里你有一个城市的列表这个列表的名字被呈现给用户。在应用程序的内部只希望处理它们的IDs因此它们通过option‘s的value属性来使用。让我们看看Rails是如何帮助输出这里的代码的。
3.1 The Select and Option Tags Select和Option标签
The most generic helper is select_tag, which — as the name implies — simply generates the SELECT tag that encapsulates an options string:
最常见的生成器helper是select_tag,它——就像名字的意思——简单的生成SELECT标签在其中封装一个选项字符串:
<%= select_tag(:city_id, ‘<option value=“1”>Lisbon</option>…’) %>
This is a start, but it doesn’t dynamically create the option tags. You can generate option tags with the options_for_select helper:
这是开始,但是它不会动态创建option标签。你可以在options_for_select helper中创建option标签:
<%= options_for_select([[‘Lisbon’, 1], [‘Madrid’, 2], …]) %>
output:
<option value=“1”>Lisbon</option>
<option value=“2”>Madrid</option>
…
The first argument to options_for_select is a nested array where each element has two elements: option text (city name) and option value (city id). The option value is what will be submitted to your controller. Often this will be the id of a corresponding database object but this does not have to be the case.
options_for_select的第一个参数是一个嵌套数组它的的每一个元素有两个元素:option text(city name)和option value(city id)。这里的option value将会被提交到你的controller中。通常这里会有id和其相应的数据库对象但是并不完全是这样。
Knowing this, you can combine select_tag and options_for_select to achieve the desired, complete markup:
知道这些,你可结合select_tag和options_for_select到达预期的(目标),完成markup:
<%= select_tag(:city_id, options_for_select(…)) %>
options_for_select allows you to pre-select an option by passing its value.
options_for_select允许你预选择一个选项通过它的值。
<%= options_for_select([[‘Lisbon’, 1], [‘Madrid’, 2], …], 2) %>
output:
<option value=“1”>Lisbon</option>
<option value=“2” selected=“selected”>Madrid</option>
…
bellow is my code in templates:
<!—it not work—>
<%= select_tag(:city_id, ‘<option value=“1”>Lisbon</option><option value=“2”>Madrid</option>’) %>
<%= options_for_select([[‘Lisbon’, 1], [‘Madrid’, 2] ], 2)%>
combine select_tag and options_for_select combine select_tag and options_for_select:<br />
<%= select_tag(:city_id, options_for_select([[‘Lisbon’, 1], [‘Madrid’, 2] ], 2)) %>
Whenever Rails sees that the internal value of an option being generated matches this value, it will add the selected attribute to that option.
无论何时Rails发现开始创建的option tag的值匹配option内部的值(设定的默认选中的值),
,将会添加selected属性到这个选项。
The second argument to options_for_select must be exactly equal to the desired internal value. In particular if the value is the integer 2 you cannot pass “2” to options_for_select — you must pass 2. Be aware of values extracted from the params hash as they are all strings.
options_for_select的第二个参数必须准确等于预期的内部的值。特别是如果这个值是整数2你不能传送“2”给options_for_select——你必须传送2。在这个值来自params hash的时候你必须保持清醒因为它们全都是strings。
3.2 Select Boxes for Dealing with Models使用Select Boxes来处理Models#外键的select boxes
In most cases form controls will be tied to a specific database model and as you might expect Rails provides helpers tailored for that purpose. Consistent with other form helpers, when dealing with models you drop the _tag suffix from select_tag:
在大多数情况中form controls将会被捆绑到一个指定的数据库model并且正如你可能期望Rails为捆绑的这个models提供量身定制的helpers。与其他form helpers一致的,当在处理models的时候你从select_tag 抛弃_tag后缀。
controller:
@person = Person.new(:city_id => 2)
view:
<%= select(:person, :city_id, [[‘Lisbon’, 1], [‘Madrid’, 2], …]) %>
Notice that the third parameter, the options array, is the same kind of argument you pass to options_for_select. One advantage here is that you don’t have to worry about pre-selecting the correct city if the user already has one — Rails will do this for you by reading from the @person.city_id attribute.
注意上面的第三个参数,这个选项数组,是相同的类型的参数你提供给options_for_select(注意其中的省略号,它是省略了一些选项没有写出但是实际中不能这样写哦有就全部给出)。这里的一个优势就是你不用必须担心预选择正确的城市如果用户已经有一个——Rails将会通过读取@person.city_id属性替你这些事情。
As with other helpers, if you were to use the select helper on a form builder scoped to the @person object, the syntax would be:
如同其他helpers,如果你打算在一个作用域为@person对象的form builder使用select helper,语句将会是:
select on a form builder
<%= f.select(:city_id, …) %>
If you are using select (or similar helpers such as collection_select, select_tag) to set a belongs_to association you must pass the name of the foreignkey (in the example above city_id), not the name of association itself. If you specify city instead of city_id Active Record will raise an error along the lines of ActiveRecord::AssociationTypeMismatch: City(#17815740) expected, got String(#1138750) when you pass the params hash to Person.new or update_attributes. Another way of looking at this is that form helpers only edit attributes. You should also be aware of the potential潜在security ramifications后果of allowing users to edit foreign keys directly. You may wish to consider the use of attr_protected and attr_accessible. For further details on this, see the RubyOnRailsSecurityGuide.
you must pass the name of the foreignkey (in the example above city_id), not the name of association itself. 你可以考虑使用attr_protected and attr_accessible.
3.3 Option Tags from a Collection of Arbitrary Objects 任意集合对象的Option 标签
Generating options tags with options_for_select requires that you create an array containing the text and value for each option. But what if you had a City model (perhaps an Active Record one) and you wanted to generate option tags from a collection of those objects? One solution would be to make a nested array by iterating over them:
通常情况下options_for_select的option标签需要你创建一个包含text和每个选项的的值的数组。但是如果你有一个City model(可能是Active Record中的一个)同时你想生成这些对象集合的选项?一个解决办法是产生一个迭代所有对象的嵌套数组:
<% cities_array = City.all.map { |city| [city.name, city.id] } %>
<%= options_for_select(cities_array) %>
This is a perfectly Pairs passed to options_for_select should have the name first and the id second, however with options_from_collection_for_select the first argument is the value method and the second the text method.valid solution, but Rails provides a less verbose alternative: options_from_collection_for_select. This helper expects a collection of arbitrary objects and two additional arguments: the names of the methods to read the option value and text from, respectively分别:
这是一个完美有效的解决方法,但是Rail提供一个更少累赘替代上面的方法:options_from_collection_for_select. 这个helper预订一个任意对象的集合和两个额外的参数:方法的name来分别读取option的value和text:
<%= options_from_collection_for_select(City.all, :id, :name) %>
As the name implies, this only generates option tags. To generate a working select box you would need to use it in conjunction with select_tag, just as you would with options_for_select. When working with model objects, just as select combines select_tag and options_for_select, collection_select combines select_tag with options_from_collection_for_select.
正如其名,它仅仅生成option tags。要生成一个能够工作的select box你还需将其关联到select_tag,就像你处理options_for_select一样的。当在model对象中工作的时候,就像select联合select_tag与options_for_select的情行,collection_select联合select_tag与options_from_collection_for_select.#这里好像说的是外键的select boxes
<%= collection_select(:person, :city_id, City.all, :id, :name) %>
To recap, options_from_collection_for_select is to collection_select what options_for_select is to select.
概括一下,options_from_collection_for_select对于collection_select正如options_for_select对于select。
Pairs passed to options_for_select should have the name first and the id second, however with options_from_collection_for_select the first argument is the value method and the second the text method.
3.4 Time Zone and Country Select时区和国家选择
To leverage time zone support in Rails, you have to ask your users what time zone they are in. Doing so would require generating select options from a list of pre-defined TimeZone objects using collection_select, but you can simply use the time_zone_select helper that already wraps this:
在Rails利用时区支持,你必须询问你的用户他们处在什么时区。要这样做将在使用collection_select的时候require来自预先定义列表中的一个TimeZome 对象的创建select选项,但是你可以简单的使用time_zone_select helper它已经包含了这些:
<%= time_zone_select(:person, :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.
这里同样也有also time_zone_options_for_select helper来手动的做这些(因此更具定制可能)。阅读API文档来了解这两个方法可能的参数。
Rails used to have a country_select helper for choosing countries, but this has been extracted to the country_selectplugin. When using this, 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通常使用一个country_select来选择国家,但是这是从country_selectplugin提取的。当使用这些,要知道来自list中排除或者列入的一些names可能有些争议(并且这也是这个功能从Rails中提取出来的原因)。
4 Using Date and Time Form Helpers
The date and time helpers differ from all the other form helpers in two important respects:
date and time helpers与其他所有的form helpers都不相同(着重)表现在两个重要的方面:
- Dates and times are not representable by a single input element. Instead you have several, one for each component (year, month, day etc.) and so there is no single value in your params hash with your date or time.
Dates and times不仅仅表现为单个input element。对于每个组件中的一个(year,month,day ect)取而代之你都有一些(element)。因此在你的params hash字典中没有你的date or time的单个值。
- Other helpers use the _tag suffix to indicate说明whether a helper is a barebones helper or one that operates on model objects. With dates and times, select_date, select_time and select_datetime are the barebones helpers, date_select, time_select and datetime_select are the equivalent model object helpers. #交换了一下顺序
其他helpers使用_tag后缀来说明一个helper是单纯的helper还是一个model对象的那样的操作。
Both of these families of helpers will create a series of select boxes for the different components (year, month, day etc.).
这些helper的组员将会创建一系列的对应于不同的组件的select boxes(year, month, day etc.)。
4.1 Barebones Helpers
The select_* 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
譬如select_* helpers成员获取Date实例作为它们的第一个变量,Time or DateTime使用的是当前选择的值。你可能忽略这个参数,在这种情况中current date会被使用。例如
<%=
select_date
Date.today,
:prefix
=>
:start_date
%>
outputs (with actual option values omitted for brevity)为了简洁省略了实际的选项值#省略号应该是相应的实际的日期和时间
<select id=“start_date_year” name=“start_date[year]”> … </select>
<select id=“start_date_month” name=“start_date[month]”> … </select>
<select id=“start_date_day” name=“start_date[day]”> … </select>
The above inputs would result in params[:start_date] being a hash with keys :year, :month, :day. To get an actual Time or Date object you would have to extract these values and pass them to the appropriate constructor, for example
完整的输入结果将会在params[:start_date]他会是一个关键字是:year, :month, :day的hash字典。要得到一个实际的Time or Date对象你将不得不提取这些值并且转换他们为适合的结构,例如:
Date.civil(params[:start_date][:year].to_i, params[:start_date][:month].to_i, params[:start_date][:day].to_i)
The :prefix option is the key used to retrieve the hash of date components from the params hash. Here it was set to start_date, if omitted it will default to date.
:prefix选项是用来接收来自params hash的hash形式的date组件的关键。这里它被设置为start_date,如果省略形式的话默认是date。
4.2 Model Object Helpers
select_date 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:
select_date(这个是单纯的helper)在update or create Active Record对象的时候预置每个params hash字典的element对应到一个属性不会很好的工作。Dates and times 的model object helpers提交参数通过指定的names,当Active Record发现这些参数时,它知道它们必须结合其他参数以及每一列(属性year, month, day etc.)被给予一个合适的结构。例如:
<%= date_select :person, :birth_date %>
outputs (with actual option values omitted for brevity)将实际的option的values忽略以精简
<select id=“person_birth_date_1i” name=“person[birth_date(1i)]”> … </select>
<select id=“person_birth_date_2i” name=“person[birth_date(2i)]”> … </select>
<select id=“person_birth_date_3i” name=“person[birth_date(3i)]”> … </select>
which results in a params hash like
{:person => {‘birth_date(1i)’ => ‘2008’, ‘birth_date(2i)’ => ‘11’, ‘birth_date(3i)’ => ‘22’}}
When this is passed to Person.new (or update_attributes), Active Record spots that these parameters should all be used to construct the birth_date attribute and uses the suffixed information to determine in which order it should pass these parameters to functions such as Date.civil.
当这些信息提交给Person.new(update_attributes),Active Record指出所有的这些参数应该使用于birth_date attribute 结构并且使用后缀声明使得它能够传递这些参数给功能(方法)例如Date.civil。
4.3 Common Options
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 :start_year and :end_year options override this. For an exhaustive list of the available options, refer to the APIdocumentation.
helpers的所有成员都使用相同的core set of functions来构建个体的select 标签因此同样能够接收大量相同的options。以其一为例,默认情况下year options中Rails将会创建在当前年份的上和下5年。如果这不是一个合适的范围,:start_year and :end_year选项将会覆盖默认的范围。要得到可用选项的全面的列表,参考APIdocumentation。
As a rule of thumb you should be using date_select when working with model objects and select_date in other cases, such as a search form which filters results by date.
一个规则指引你在处理model objects的时候使用date_select在其他情况的时候使用select_date,比如一个search form它过滤日期作获取结果。
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.
在许多情况下,内置的日期选择器是笨拙的,因为他们对计算出日期和工作日关系的用户没有援助。
4.4 Individual Components个体组件
Occasionally you need to display just a single date component such as a year or a month. Rails provides a series of helpers for this, one for each component select_year, select_month, select_day, select_hour, select_minute, select_second. These helpers are fairly straightforward. By default they will generate an input field named after the time component (for example “year” for select_year, “month” for select_month etc.) although this can be overridden with the :field_name option. The :prefix option works in the same way that it does for select_date and select_time and has the same default value.
偶然情况下你需要仅仅显示单个日期组件如year or month。Rails提供一些helpers来做这些,给每一个组件select_year, select_month, select_day, select_hour, select_minute, select_second。这些helpers相当的简单。默认情况下他们将会创建一个input field并以时间组件命名(例如 “year” for select_year, “month” for select_month etc.)即使这会覆盖:field_name选项。:prefix以一样的方式工作,对于select_date and select_time会设置同样的默认值。
<%= select_year(2011) %>
<%= select_year(Time.now) %>
will produce the same output if the current year is 2011 and the value chosen by the user can be retrieved by params[:date][:year].
5 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 rendered form’s encoding MUST be set to “multipart/form-data”. If you use form_for, this is done automatically. If you use form_tag, you must set it yourself, as per the following example.
The following two forms both upload a file.
一个常用的任务是上传一些种类的文件,无论在上传进程中的是一个个人图片还是一个包含数据CSV文件。文件上传中重点要注意的事情是rendered 表单的编码必须被设置成是“multipart/form-data”. 如果你使用的form_for,这将被自动完成。如果你使用form_tag,你必须自己设置它,在随后的每个例子中。后面的两个表单都是上传一个文件。
<%= form_tag({:action => :upload}, :multipart => true) do %>
<%= file_field_tag ‘picture’ %>
<% end %>
<%= form_for @person do |f| %>
<%= f.file_field :picture %>
<% end %>
Since Rails 3.1, forms rendered using form_for have their encoding set to multipart/form-data automatically once a file_field is used inside the block. Previous versions required you to set this explicitly.
从Rails3.1,form使用form_for来render一旦在block中有一个file_field被使用编码自动设置为multipart/form-data。以前的版本需要你准确的设置为这样的编码。
Rails provides the usual pair of helpers: the barebones file_field_tag and the model oriented file_field. 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 params[:picture] and in the second case in params[:person][:picture].
R爱丽丝提供通常配对的helpers:单个的file_field_tag和面向model的file_field。
这与其他的helpers的不同是你不能为file inputs设置一个不同的值因为这样没有意义。正如你所期望的第一种情况上传的文件在params[:picture],第二种情况在params[:person][:picture]中。
5.1 What Gets Uploaded
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 original_filename attribute containing the name the file had on the user’s computer and a content_type attribute containing the MIME type of the uploaded file. The following snippet saves the uploaded content in #{Rails.root}/public/uploads under the same name as the original file (assuming the form was the one in the previous example).
在params hash中的对象是IO子类的一个实例。取决于上传文件的大小它可能实际上是一个StringIO或者临时文件的备份文件。在这两个情况中对象将会有一个original_filename属性包含文件在用户电脑上的名字以及一个content_type属性包含上传文件的MIME形式。随后的阶段保存上传的内容在#{Rails.root}/public/uploads并以与原始名字相同(假设form是一个预先的例子则下面是其控制函数)
def upload
uploaded_io = params[:person][:picture]
File.open(Rails.root.join(‘public’, ‘uploads’, uploaded_io.original_filename), ‘w’) do |file|
file.write(uploaded_io.read)
end
end
Once a file has been uploaded, there are a multitude of potential潜在tasks, ranging from where to store the files (on disk, Amazon S3, etc) and associating them with models to resizing image files and generating thumbnails. The intricacies of this are beyond the scope of this guide, but there are several libraries designed to assist with these. Two of the better known ones are CarrierWave and Paperclip.
一旦一个文件被上传,这里有多个潜在的任务,响应在哪里存放文件(on disk, Amazon S3, etc) 并且关联它们至models为重设大小的图片文件同时创建缩略图。这里的复杂远超这个guide的范围,但是这里有一些库被设计来分派这些。有两个较好的库ones are CarrierWave and Paperclip。
Iftheuserhasnotselectedafilethecorrespondingparameterwillbeanemptystring.
5.2 Dealing with Ajax处理Ajax
Unlike other forms making an asynchronous file upload form is not as simple as providing form_for with :remote => true. 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.
与其他forms不同制作一个异步文件上传表单不能简单的提供form_for with :remote => true.一个Ajax表单这个序列被在浏览器内部运行的JavaScript完成同时因为JavaScript不能从你的硬盘中读取文件这个文件就不能上传。最常见的解决方法是使用一种无形的iframe服务于目标forms的提交。
6 Customizing 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 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
正如开始提到的object yielded by form_for以及是FormBuilder的实例(或者其中的子类的实例)。Form builders封装表单元素的显示notion为一个单独的对象。然而你当然你也可以为你的form编写helpers通常的方式你可以通过(编写)FormBuilder的子类并且在这里添加helpers。例如:
<%= form_for @person do |f| %>
<%= text_field_with_label f, :first_name %>
<% end %>
可以替换为:
<%= form_for @person, :builder => LabellingFormBuilder do |f| %>
<%= f.text_field :first_name %>
<% end %>
by defining a LabellingFormBuilder class similar to the following:
通过定义一个LabellingFormBuilder类与接下来的类似:
class LabellingFormBuilder < ActionView::Helpers::FormBuilder
def text_field(attribute, options={})
label(attribute) + super
end
end
If you reuse this frequently you could define a labeled_form_for helper that automatically applies the :builder => LabellingFormBuilder option.
如果你拒绝这样频繁的操作你可以定义一个labeled_form_for它会自动的应用:builder => LabellingFormBuilder选项。
The form builder used also determines what happens when you do
form builer的使用也决定了在你操作的时候将会发生什么
<%= 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.
如果f是FormBuilder的一个实例那么这里将会局部的render表单,为form buider设置partial’s对象。如果form builder是LabellingFormBuilder那么在render中labelling_form将会替代f。
7 Understanding Parameter Naming Conventions明白参数公约
As you’ve seen in the previous sections, values from forms can be at the top level of the params hash or 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.
正如你在(本节guide)前面部分看到的,来至forms的值将会在顶级的parmas hash字典内或者是嵌套在另一个hash子典中。例如在Person model的一个标准的create action中,params[:model]通常将会有一个含有创建的person的所有属性的字典。params字典也可以包含数组,由hash字典组成的数组等等。
Fundamentally HTML forms don’t know about any sort of structured data, all they generate is name–value pairs, where pairs are just plain strings. The arrays and hashes you see in your application are the result of some parameter naming conventions that Rails uses.
归根结底HTML forms并不知道关于数据结构的任何类型,它们生成的所有仅是name-value对,这些(name-value)仅仅是纯string。你在应用程序中看到的数组和hash字典是一些在Rails使用的参数命名公约的结果。
You may find you can try out examples in this section faster by using the console to directly invoke Rails’ parameter parser. For example,
你会发现你可以快速的尝试这部分的例子通过使用console来直接的调用Rails’s parameter 解析器。例如,
ActionController::UrlEncodedPairParser.parse_query_parameters “name=fred&phone=0123456789”
=> {“name”=>“fred”, “phone”=>“0123456789”}
7.1 Basic Structures基础的strcutures
The two basic structures are arrays and hashes. Hashes mirror the syntax used for accessing the value in params. For example if a form contains
两个根本的结构是arrays和hash字典。Hash字典镜像这种语法用来访问params的值。例如如果一个form中包含
<input id=“person_name” name=“person[name]” type=“text” value=“Henry”/>
the params hash will contain
{‘person’ => {‘name’ => ‘Henry’}}
and params[:person][:name] will retrieve the submitted value in the controller.
同时params[:person][:name]将会在controller中接收提交的value。
Hashes can be nested as many levels as required, for example
如果需要hash字典可以嵌套多层,例如
<input id=“person_address_city” name=“person[address][city]” type=“text” value=“New York”/>
will result in the params hash being将会在params hash字典中返回
{‘person’ => {‘address’ => {‘city’ => ‘New York’}}}
Normally Rails ignores duplicate parameter names. If the parameter name contains an empty set of square brackets [] then they will be accumulated in an array. If you wanted people to be able to input multiple phone numbers, you could place this in the form:
正常情况下Rails忽略重复参数名称。如果参数名包含一个空的[]那么它们会在一个数组中累积。如果你想people能够输入多个电话号码,你可以将这里放入form中:
<input name=“person[phone_number][]” type=“text”/>
<input name=“person[phone_number][]” type=“text”/>
<input name=“person[phone_number][]” type=“text”/>
This would result in params[:person][:phone_number] being an array.
7.2 Combining Them联合它们
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
我们可以总结出两个概念。例如,一个element的hash键值可能是作为一个先前例子的hash键值的数组,或者你也可以有一个hash字典的数组。例如一个form可以让你创建任何数量的地址通过重复随后的form 片段
<input name=“addresses[][line1]” type=“text”/>
<input name=“addresses[][line2]” type=“text”/>
<input name=“addresses[][city]” type=“text”/>
This would result in params[:addresses] being an array of hashes with keys line1, line2 and city. Rails decides to start accumulating values in a new hash whenever it encounters an input name that already exists in the current hash.
这里返回的结果在params[:addresses]中,是一个hash字典组成的数组其中keys是line1,line2和city。 Rails决定开始在一个新的hash中积累值不管它是不是遇到一个已经在当前的hash已经存在的input name。
There’s a restriction, however, while hashes can be nested arbitrarily, only one level of “arrayness” is allowed. Arrays can be usually replaced by hashes, for example instead of having an array of model objects one can have a hash of model objects keyed by their id, an array index or some other parameter.
这是一个限制,然而,即使hashes能够嵌套任意层,只有一级的“arrayness”是被允许的。数组通常可以替换hashes字典,例如作为替代,一个数组的model对象可以键入它们的id,一个array index或者一些其他参数。
Array parameters do not play well with the check_box 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 check_box helper fakes this by creating an auxiliary hidden input with the same name. If the checkbox is unchecked only the hidden input is submitted and if it 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 array element. It is preferable to either use check_box_tag or to use hashes instead of arrays.
数组参数在check_box helper中不能得到很好的效果。根据HTML规范的unchecked checkboxes提交空值。无论如何一个checkbox提交一个值通常非常方便。check_box helper 假想这种情况来创建具有相同name一个辅助的隐藏input。如果checkbox是unchecked那么只有hidden input被提交如果它是check那么两个都会提交但是checkbox优先提交value.当(Rails)工作到有这两个重复提交的参数数组rails将会产生混淆,因为重复 input name会开始一个新的数组元素。这里使用 check_box_tag或者使用hash替代array都是可取的。
7.3 Using Form Helpers
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 text_field_tag Rails also provides higher level support. The two tools at your disposal here are the name parameter to form_for and fields_for and the :index option that helpers take.
前面的部分根本没有使用Rails form helpers。然而你可以自己加工input name并且直接传输他们给helpers例如 text_field_tag Rails也提供更高级别的支持。有两个工具供你差遣它们是获取:name的form_for和获取:index选项的fields_for helpers。
You might want to render a form with a set of edit fields for each of a person’s addresses. For example:
你可能想render一个person’s addresses form并且对person’s each addresses使用一样的edit fields。
<%= form_for @person do |person_form| %>
<%= person_form.text_field :name %>
<% @person.addresses.each do |address| %>
<%= person_form.fields_for address, :index => address do |address_form|%>
<%= address_form.text_field :city %>
<% end %>
<% end %>
<% end %>
Assuming the person had two addresses, with ids 23 and 45 this would create output similar to this:
假设person有两个address。id为23和45将会创建与下面类似的HTML代码:
<form accept-charset=“UTF-8” action=“/people/1” id=“edit_person_1” method=“post”>
<input id=“person_name” name=“person[name]” size=“30” type=“text” />
<input id=“person_address_23_city” name=“person[address][23][city]” size=“30” type=“text” />
<input id=“person_address_45_city” name=“person[address][45][city]” size=“30” type=“text” />
</form>
This will result in a params hash that looks like
{‘person’ => {‘name’ => ‘Bob’, ‘address’ => {‘23’ => {‘city’ => ‘Paris’}, ‘45’ => {‘city’ => ‘London’}}}}
Rails knows that all these inputs should be part of the person hash because you called fields_for on the first form builder. By specifying an :index option you’re telling Rails that instead of naming the inputs person[address][city] it should insert that index surrounded by [] between the address and the city. If you pass an Active Record object as we did then Rails will call to_param on it, which by default returns the database id. This is often useful as it is then easy to locate which Address record should be modified. You can pass numbers with some other significance, strings or even nil (which will result in an array parameter being created).
Rails知道这里所有的inputs应该是person hash的一部分因为你在form builder的开始调用了 fields_for。通过指定:index选项你告诉Rails替代person[address][city] input中的名字它将会在address和此帖有之间插入被[]包围的index。如果你通过的是一个Active Record object正如我们知道的Rails将会调用_param,它会默认返回数据库的(city的)id。这在当Addrss记录需要修改,的时候非常有用它能易于定位。你可以传递给其他意义的数字,字符串或者空(它将返回在创建的参数数组中)。
To create more intricate复杂 nestings, you can specify the first part of the input name (person[address] in the previous example) explicitly, for example
<%= fields_for ‘person[address][primary]’, address, :index => address do |address_form| %>
<%= address_form.text_field :city %>
<% end %>
will create inputs like
As a general rule the final input name is the concatenation of the name given to fields_for/form_for, the index value and the name of the attribute. You can also pass an :index option directly to helpers such as text_field, but it is usually less repetitive to specify this at the form builder level rather than on individual input controls.
As a shortcut you can append [] to the name and omit忽略 the :index option. This is the same as specifying :index => address so
<%= fields_for ‘person[address][primary][]’, address do |address_form| %>
<%= address_form.text_field :city %>
<% end %>
produces exactly the same output as the previous example.
8 Forms to external resources
If you need to post some data to an external外部 resource it is still great to build your from using rails form helpers. But sometimes you need to set an authenticity_token for this resource. You can do it by passing an :authenticity_token => ‘your_external_token’ parameter to the form_tag options:
<%= form_tag ‘http://farfar.away/form’, :authenticity_token => ‘external_token’) do %>
Form contents
<% end %>
Sometimes when you submit data to an external resource, like payment gateway, fields you can use in your form are limited by an external API. So you may want not to generate an authenticity_token hidden field at all. For doing this just pass false to the :authenticity_token option:
<%= form_tag ‘http://farfar.away/form’, :authenticity_token => false) do %>
Form contents
<% end %>
The same technique is available for the form_for too:
<%= form_for @invoice, :url => external_url, :authenticity_token => ‘external_token’ do |f|
Form contents
<% end %>
Or if you don’t want to render an authenticity_token field:
<%= form_for @invoice, :url => external_url, :authenticity_token => false do |f|
Form contents
<% end %>
9 Building Complex Forms
Many apps grow beyond simple forms editing a single object. For example when creating a Person 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:
- As of Rails 2.3, Rails includes Nested Attributes and Nested Object Forms
- Ryan Bates’ series of Railscasts on complex forms
- Handle Multiple Models in One Form from Advanced Rails Recipes
- Eloy Duran’s complex-forms-examples application
- Lance Ivy’s nested_assignment plugin and sample application
- James Golick’s attribute_fu plugin