Rails中的Helper方法

tag类的Helper

form_tag

<%= form_tag("/search", method: "get") do %>
  <%= label_tag(:q, "Search for:") %>
  <%= text_field_tag(:q) %>
  <%= submit_tag("Search") %>
<% end %>
#生成HTML如下
<form accept-charset="UTF-8" action="/search" method="get">
  <label for="q">Search for:</label>
  <input id="q" name="q" type="text" />
  <input name="commit" type="submit" value="Search" />
</form>
#生成的表单的每个input属性都有ID属性,其值和name属性的值是一样的

form_tag({controller: "people", action: "search"}, method: "get", class: "nifty_form")
#第二个hash参数为html属性
<form accept-charset="UTF-8" action="/people/search" method="get" class="nifty_form">

复选框

<%= check_box_tag(:pet_dog, "12") %>

<input id="pet_dog" name="pet_dog" type="checkbox" value="12" />

单选框

<%= radio_button_tag(:age, "child") %>

<input id="age_child" name="age" type="radio" value="child" />

处理模型对象

#如果控制器定义了@person实例变量,有属性name ="Henry"
<%= text_field(:person, :name) %>
#生成如下
<input id="person_name" name="person[name]" type="text" value="Hery" />
#params获取的值为
{'person' => {'name' => 'Henry'}}
#可以使用params[:person][:name]获取提交的值
#如果@person实例是数据库表nurse_aid_person,那么产生的代码如下
<input id="person_name" name="nurse_aid_person[name]" type="text" value="Hery" />

Hash

#Hash可以随意嵌套
<input id="person_address_city" name="person[address][city]" type="text" 
  value="New York"/>
#获取的params为
{'person'=>{'address'=>{'city'=>'New York'}}}
params[:person][:address][:city]

数组

#一般情况下Rails回忽略重复的参数名
<input name="person[phone_number][]" type="text"/>
<input name="person[phone_number][]" type="text"/>
<input name="person[phone_number][]" type="text"/>
#params[:person][:phone_number]是一个数组

Hash和数组结合

<input name="addresses[][line1]" type="text"/>
<input name="addresses[][line2]" type="text"/>
<input name="addresses[][city]" type="text"/>
#params[:addresses]值是一个由Hash组成的数组

form_for表单绑定对象

<%= 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 %>

<form action="/articles/create" method="post" class="nifty_form">
  <input id="article_title" name="article[title]" type="text" />
  <textarea id="article_body" name="article[body]" cols="60" rows="12"></textarea>
  <input name="commit" type="submit" value="Create">
</form>

fields_for方法

#同一表单中编辑多个模型对象时经常使用fields_for方法。
#eg、有个Person模型,和ContactDetail模型关联
<%= 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 %>

#生成的HTML代码如下
<form action="/people/create" class="new_person" id="new_person" method="post">
  <input id="person_name" name="person[name]" type="text" />
  <input id="contact_detail_phone_number" name="contact_detail[phone_number]" type="text" />
</form>

命名空间

#admin命名空间
form_for [:admin, @article] #admin_article_path(@article)

form_for[:admin, :management, @article]

文件处理

上传文件

#params[:picture]
<%= form_tag({action: :upload}, multipart: true) do %>
  <%= file_field_tag 'picture' %>
<% end %>

#params[:person][:picture]
<%= form_for @person do |f| %>
  <%= f.file_field :picture %>
<% end %>

处理上传

#可以使用CarrierWave和Paperclip等第三方库
def upload
  upload_io = params[:person][:picture]
  File.open(Rails.root.join('public', uploads, upload_io.original_filename), 'wb') do |file|
    file.write(uploaded_io.read)
  end
end

使用Ajax上传文件

<%= form_for @person, builder: LabellingFormBuilder do |f| %>
  <%= f.text_field :first_name %>
<% end %>
#定制表单构造器
class LabellingFormBuilder < ActionView::Helpers::FormBuilder
  def text_field(attribute, options=[])
    label(attribute) + super
  end
end

外部资源

#如果不需要access_token的话,可以关闭,如果需要,设置authenticity_token的值
<%= form_tag 'http://www.baidu.com', authenticity_token:  false do %>
...
<% end %>

复杂的表单

class Person < ActiveRecord::Base
  has_many :addresses
  accepts_nested_attributes_for :addresses, allow_destroy: true,
    reject_if: lambda{|attributes| attributes['kind'].blank?}
#自动为Person对象创建address_attributes=方法,用于创建、更新、删除地址操作
end

class Address < ActiveRecord::Base
  belongs_to :person
end

嵌套表单

<%= form_for @person do |f| %>
  Addresses:
  <ul>
    <%= fields_for @person.addresses do |addresses_form| %>
      <li>
        <%= addresses_form.label :kind %>
        <%= addresses_form.text_field :kind %>

        <%= addresses_form.label :street %>
        <%= addresses_form.text_field :street %>
      </li>
    <% end %>
  </ul>
<% end %>

如果关联支持嵌套属性,fields_for方法会为关联中的每个元素执行一遍代码块,如果没有Address,就不执行,一般做法是在控制器中构建一个或者多个空的子属性。这样至少会有一组字段显示出来。

def new
  @person = Person.new
  2.times { @person.addresses.build }
end

如果用户提交了两个地址,提交的参数如下

{
  'person' => {
    'name' => 'John Doe',
    'addresses_attributes' => {
      '0' => {
        'kind' => 'Home',
        'street' => '221b Baker Street'
      },
      '1' => {
        'kind' => 'Office',
        'street' => '31 Spooner Street'
      }
    }
  }
}

控制器端

def create
  @person = Person.new(person_params)
end

private
  def person_params
    params.require(:person).permit(:name, addresses_attributes:[:id, :kind, :street])
  end

删除属性

#表单
<%= form_for @person do |f| %>
  Addresses:
  <ul>
    <%= f.fields_for :addresses do |addresses_form| %>
      <li>
  #如果属性组成的hash中包含_destroy键,且值为1或true,就会删除对象
        <%= addresses_form.check_box :_destroy%>
        <%= addresses_form.label :kind %>
        <%= addresses_form.text_field :kind %>
        ...
      </li>
    <% end %>
  </ul>
<% end %>

修改控制器中的参数白名单

def person_params
  params.require(:person).
    permit(:name, addresses_attributes: [:id, :kind, :street, :_destroy])
end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,654评论 18 139
  • HTML表单 在HTML中,表单是 ... 之间元素的集合,它们允许访问者输入文本、选择选项、操作对象等等,然后将...
    兰山小亭阅读 3,417评论 2 14
  • 22年12月更新:个人网站关停,如果仍旧对旧教程有兴趣参考 Github 的markdown内容[https://...
    tangyefei阅读 35,181评论 22 257
  • 爬虫就是从网络上发现你想要数据的工具。 大互联网公司 我原来在互联网公司,觉得获取数据so easy。只要你需要,...
    jacksu在简书阅读 2,202评论 2 0
  • 赶着夏天的尾巴,我们来说说笔记本散热问题。笔记本电脑相比传统台式机的优势和特点就是轻薄,但因此也造成笔记本机体内部...
    玩机社阅读 468评论 1 1