Rails Form helpers

来源:互联网 发布:网络爬虫视频 编辑:程序博客网 时间:2024/05/16 15:17
最基本的form helper是form_tag: 
Ruby代码  收藏代码
  1. <% form_tag do %>   
  2.  Form contents   
  3. <% end %>   

没给form_tag传递任何参数的时候,form_tag将生成一个以当前页面为action值,以post为method值的form元素,如下: 
Html代码  收藏代码
  1. <form action="/books" method="post">  
  2.  <div style="margin:0;padding:0;display:inline">  
  3.   <input name="authenticity_token" type="hidden"   
  4.   value="1ZpTUU7D9I2lhajgvAiXlu+JwxujHl4CSfczZWh/aM4=" />  
  5.  </div>  
  6.   Form contents  
  7. </form>   

这里自动生成了一个隐藏的div,里面有一个隐藏域,name为authenticity_token,value是一个随机字符串,这个隐藏域的值是用于跨站点请求伪造保护(cross-site request forgery protection)的。关于跨站请求伪造。You can read more about this in the Ruby On Rails Security Guide

form_tag的第一个参数是表单的action值;第二个参数是个hash,可以用来设置表单的method属性和multipart、class等html属性。 

rails还提供text_field_tag、label_tag、password_field_tag、hidden_field_tag等常用表单元素的helper,利用这些helper可以组成一个完整的表单。 

通常情况下,页面的一个表单是和某个model绑定的,假如用上面这些text_field_tag等带_tag后缀的标签来绑定model,需要为这些helper指定name,示例: 
Ruby代码  收藏代码
  1. <% form_tag book_path(@book), :method => :put do%>  
  2.     <%= text_field_tag 'book[title]'@book.title %><br/>  
  3.     <%= text_field_tag 'book[author]'@book.author %><br/>  
  4.     <%= submit_tag 'Update' %>  
  5. <% end %>  

假设这里的@book有属性title='refactor',author='martin fowler'生成的 
Html代码  收藏代码
  1. <form action="/books/1" method="post">  
  2.  <div style="margin:0;padding:0;display:inline">  
  3.   <input name="_method" type="hidden" value="put" />  
  4.   <input name="authenticity_token" type="hidden"  
  5.   value="1ZpTUU7D9I2lhajgvAiXlu+JwxujHl4CSfczZWh/aM4=" />  
  6.  </div>  
  7.  <input id="book_title" name="book[title]" type="text" value="refactor"/><br/>  
  8.  <input id="book_author" name="book[author]" type="text" value="martin fowler"/><br/>  
  9.  <input name="commit" type="submit" value="Update" />  
  10. </form>  

这里边的重复代码很多,比如book[title]和@book.title。rails提供了更方便的另一系列helper,这些helper不带_tag后缀,如:text_field、text_area。这些helper的第一个参数是model实例变量的名字,第二个参数是model的方法(一般情况下就是model的属性) 

Ruby代码  收藏代码
  1. <% form_tag book_path(@book), :method => :put do%>  
  2.     <%= text_field :book:title %><br/>  
  3.     <%= text_field :book:author %><br/>  
  4.     <%= submit_tag 'Update' %>  
  5. <% end %>  

这段erb代码和之前的*_tag生成的html差不多。并不是完全一样: 
Html代码  收藏代码
  1. <form action="/books/1" method="post">  
  2.  <div style="margin:0;padding:0;display:inline">  
  3.   <input name="_method" type="hidden" value="put" />  
  4.   <input name="authenticity_token" type="hidden"  
  5.   value="1ZpTUU7D9I2lhajgvAiXlu+JwxujHl4CSfczZWh/aM4=" />  
  6.  </div>  
  7.  <input id="book_title" name="book[title]" size="30" type="text" value="refactor" /><br/>  
  8.  <input id="book_author" name="book[author]" size="30" type="text" value="martin fowler" /><br/>  
  9.  <input name="commit" type="submit" value="Update" />  
  10. </form>  

这段erb代码比较之前的干净多了,但是这里还有重复代码:model的名字。rails提供了form_for来消除这个重复:
Ruby代码  收藏代码
  1. <% form_for :book@book:url=>book_path(@book), :html=>{:method=>:putdo |f| %>  
  2.     <%= f.text_field :title%><br/>  
  3.     <%= f.text_field :author%><br/>  
  4.   <%= f.submit 'Update' %>  
  5. <% end %>  

这段代码也能达到之前的效果,注意这里的text_field等方法是block内参数f的方法。form_for的第一个参数是model的名字,第二个参数是一个model的实例(一般来自controller),如果这个实例的变量名和model名一样,可以把第2个参数省略掉,写成这样:
Ruby代码  收藏代码
  1. <% form_for :book:url=>book_path(@book), :html=>{:method=>:putdo |f| %>  

假如表单中有相关联的其它model的属性,还可以使用fields_for: 
Ruby代码  收藏代码
  1. <% form_for :person:url=>person_path(@person), :html=>{:method=>:putdo |f| %>  
  2.   name:<%= f.text_field :name %><br/>  
  3.   <%fields_for @person.address do |address|%>  
  4.   city:<%=address.text_field :city%><br/>  
  5.   street:<%=address.text_field :street%><br/>  
  6.   <%end%>  
  7.   <%= f.submit 'Update' %>  
  8. <% end %>  

fields_for的用法跟form_for差不多,以上代码生成如下HTML: 
Html代码  收藏代码
  1. <form action="/people/2" method="post">  
  2.  <div style="margin:0;padding:0;display:inline">  
  3.   <input name="_method" type="hidden" value="put" />  
  4.   <input name="authenticity_token" type="hidden"  
  5.   value="hJMxllYlzx0oWi2swhw1Hq3P3yfYMMwL+KXdjOBwXmM=" />  
  6.  </div>   
  7.  name:<input id="person_name" name="person[name]" size="30" type="text" value="bob" /><br/>     
  8.  city:<input id="address_city" name="address[city]" size="30" type="text" /><br/>   
  9.  street:<input id="address_street" name="address[street]" size="30" type="text" /><br/>     
  10.  <input id="person_submit" name="commit" type="submit" value="Update" />   
  11. </form>   

其中city和street的值可以在controller通过params[:address]取得。 

Rails2.3开始支持嵌套的对象表单(Nested Object Form)。在update操作的时候,上面的表单在controller里必须通过@person.address.build(params[:address])来更新address。使用嵌套对象表单可以直接通过@person.update_attributes(params[:person])一句代码来同时完成@person以及@person.address的更新。要使用嵌套对象表单首先要给model添加一句代码,比如这里的Person类: 
Ruby代码  收藏代码
  1. class Person < ActiveRecord::Base  
  2.     has_one :address  
  3.     accepts_nested_attributes_for :address  
  4. end  

这里加了一句accepts_nested_attributes_for方法的调用,erb代码可以这样写: 
Ruby代码  收藏代码
  1. <% form_for @person:url=>person_path(@person), :html=>{:method=>:putdo |f| %>  
  2.   name:<%= f.text_field :name %><br/>  
  3.   <%f.fields_for :address do |address|%>  
  4.   city:<%=address.text_field :city%><br/>  
  5.   street:<%=address.text_field :street%><br/>  
  6.   <%end%>  
  7.   <%= f.submit 'Update' %>  
  8. <% end %>  

再次注意这里的fields_for,是form_for方法的block里参数f的方法。 
生成的HTML: 
Html代码  收藏代码
  1. <form action="/people/2" class="edit_person" id="edit_person_2" method="post">  
  2.  <div style="margin:0;padding:0;display:inline">  
  3.   <input name="_method" type="hidden" value="put" />  
  4.   <input name="authenticity_token" type="hidden"   
  5.   value="hJMxllYlzx0oWi2swhw1Hq3P3yfYMMwL+KXdjOBwXmM=" />  
  6.  </div>   
  7.  name:<input id="person_name" name="person[name]" size="30" type="text" value="bob" /><br/>   
  8.  <input id="person_address_attributes_id" name="person[address_attributes][id]" type="hidden" value="1" />   
  9.  city:<input id="person_address_attributes_city" name="person[address_attributes][city]" size="30" type="text" value="sanming" /><br/>   
  10.  street:<input id="person_address_attributes_street" name="person[address_attributes][street]" size="30" type="text" value="xxstreet" /><br/>   
  11.     
  12.  <input id="person_submit" name="commit" type="submit" value="Update" />   
  13. </form>   

对比之前的那段HTML,不难发现,这段HTML多了一个隐藏域,用来存放address的id: 
Html代码  收藏代码
  1. <input id="person_address_attributes_id" name="person[address_attributes][id]" type="hidden" value="1" />  

同时,city、street输入框的id和name属性和之前也不一样了。比较郁闷的是,Nested Object Form似乎只对update操作有效,create操作就不行,因为在new的页面上得不到address的id,会出现“You have a nil object when you didn't expect it!“。因此,new页面只好使用前面关于fields_for方法的第一个例子中的方式来创建表单了。(仍然有解决的办法:http://www.pixellatedvisions.com/2009/03/18/rails-2-3-nested-model-forms-and-nil-new-record 只要在fields_for之前build_address即可。) 

还要注意的是,使用Nested Object Form的时候,form_for的第一个参数不能再是symbol,而必须是一个object,假如使用symbol :person,生成的HTML会变成下面这样: 
Html代码  收藏代码
  1. <form action="/people/2" method="post">  
  2.  <div style="margin:0;padding:0;display:inline">  
  3.   <input name="_method" type="hidden" value="put" />  
  4.   <input name="authenticity_token" type="hidden"  
  5.   value="hJMxllYlzx0oWi2swhw1Hq3P3yfYMMwL+KXdjOBwXmM=" />  
  6.  </div>   
  7.  name:<input id="person_name" name="person[name]" size="30" type="text" value="bob" /><br/>     
  8.  city:<input id="person_address_city"  
  9.  name="person[address][city]" size="30" type="text" /><br/>   
  10.  street:<input id="person_address_street"  
  11.  name="person[address][street]" size="30" type="text" /><br/>     
  12.  <input id="person_submit" name="commit" type="submit" value="Update" />   
  13. </form>   

少了那个隐藏域,而且city和street输入框的id和name属性又不一样了,这样的表单提交之后会出现TypeMismatch Exception。见:http://stackoverflow.com/questions/742536/rails-nested-object-form-attributes-problem 

accepts_nested_attributes_for方法的调用会为该类的实例生成一个名为*_attributes=的writer method。详见Rails API中fields_for方法的Nested Attributes Example部分。 

最后,RESTful的应用中,对作为资源的model,form_for方法用起来更简单: 
Ruby代码  收藏代码
  1. <%form_for(@persondo |f|%>  
  2. .....  
  3. <%end%>  

这里生成的form元素根据@person的状态来设置action属性:如果@person.new_record?返回true,action中使用的相应的path就是people_path,并且method属性将被设置为post;否则action中使用的相应的path是person_path(@person),并且method属性将被设置为put。再仔细观察,两种情况下form元素的id和class值也会不同:
引用
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.


使用了命名空间(namespace)的resource由于path/url helper与未使用命名空间的resource的path/url helper不同,直接使用form_for(@blog)会找不到blogs_path方法。这种情况下可以这样使用form_for: 
Ruby代码  收藏代码
  1. <% form_for [:admin@blog]) do |f|%>  
  2. ...  
  3. <% end %>  

这里会自动使用admin_blogs_path或者admin_blog_path(@blog)(视@blog.new_record?的返回值而定),相当于: 
Ruby代码  收藏代码
  1. <% form_for(:blog@blog:url=>admin_blogs_path) do |f|%>  
  2. ...  
  3. <% end %>  

或 
Ruby代码  收藏代码
  1. <% form_for(:blog@blog:url=>admin_blog_path(@blog), :html=>{:method=>:put}) do |f|%>  
  2. ...  
  3. <% end %>  
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 碰上职业打假的怎么办 遇到专业打假的怎么办 手机wifi被劫持怎么办 手机网页乱跳怎么办 老公说话不算话怎么办 编曲接不到活怎么办 电表显示跳闸黄灯怎么办 硫酸铬钾中毒怎么办 门锁能扭动却打不开怎么办 防盗门保险坏了怎么办 厦门工会卡过期怎么办 阴雨天被子受潮怎么办 衣服晾臭了怎么办 喷砂机油水分离泵有油怎么办 水太烫玻璃瓶盖打不开怎么办 玻璃罐的玻璃盖打不开怎么办? 开红酒没有开瓶器怎么办 手机卡突然坏了怎么办 滚筒洗衣机打不开门怎么办 全自动洗衣机门开不开怎么办 好期待评分不足怎么办 单片机数码管亮度低怎么办 猫的同轴灯不亮怎么办 楼下邻居太吵怎么办 冰箱冷却液内露怎么办 冷却水没有了会怎么办 金立m7信号不好怎么办 csgo凉了饰品怎么办 模型拟合度低怎么办 石膏线用发泡胶怎么办 电表上显示err10怎么办 电表显示欠压怎么办 tcl电视遥控器失灵怎么办 玩具汽车遥控器失灵怎么办 玩具车遥控丢了怎么办 按压扣坏了怎么办 电脑用不了鼠标怎么办 多肉上的肉虫子怎么办 警察被取消警衔怎么办 隐形眼镜带歪了怎么办 gta5正在加载慢怎么办