在寫網站的過程當中,時常會用到nested model form。而因爲nested model form牽扯的東西比較多,理解起來並不容易。我打算從最簡單的form講起,介紹一下nested model form是如何工做的,以及一些常見的問題。html
經過form更新實例的流程大致是這樣的,咱們使用FormHelper來構建form,Rails會將form內的數據以'hash'的形式放入parmas;參數(params)被permit後,經過方法調用的方式,賦值給某個實例。ruby
我將從後向前解釋這個流程post
params被permit後,咱們通常會調用assign_attribute,對實例進行賦值。
而assign_attributes
最終調用了_assign_attribute
,網站
只考慮最簡單的狀況的話,_assign_attribute
的代碼將會是這樣的:ui
def _assign_attribute(k, v) public_send("#{k}=", v) end
能夠被這樣調用_assign_attribute(:name, "2dian718")
code
這個方法是經過k(key)找到對應的setter方法,並傳入v(value)。orm
assign_attributes
內調用了sanitize_for_mass_assignment(給大量賦值消消毒)
,其做用是檢查傳入的參數是否有被permit。
若是沒有,則拋出異常ActiveModel::ForbiddenAttributesError
。htm
ActionController::Parameters在初始化的時候,params的@permitted
被設置爲false。因此咱們想用params進行賦值的時候,必須先要對參數進行permit。對象
咱們能夠用ActionController::Parameters.permit_all_parameters = true
來改變這個默認行爲。token
<%= form_for(@company) do |f| %> <%= f.text_field :name %> <%= f.submit %> <% end %>
將會生成
<form class="new_company" id="new_company" action="/companies" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="NeSXiKXJcMAyFcGQWfTDGE/7q21QWGjQoYN7IABUIFlnFkAtHFiv9PAjDaUOB0lu0pq7pDRj0JHsz+0jLJGDdw=="> <input type="text" name="company[name]" id="company_name"> <input type="submit" name="commit" value="Create Company"> </form>
咱們看到 <%= f.text_field :name %>
被解釋成了<input type="text" name="company[name]" id="company_name">
請注意,form_for的do後面跟了一個f
關於這個 f
, rails的文檔裏是這樣解釋的,form_for會吐出來(yield)一個form builder的對象(就是那個f
),他既瞭解form,也瞭解model(會在下文進行詳細介紹)。
咱們也能夠定製一個form builder,好比說給input自動加上標籤,代碼以下。
class LabellingFormBuilder < ActionView::Helpers::FormBuilder (field_helpers - [:label, :check_box, :radio_button, :fields_for, :hidden_field, :file_field]).each do |selector| class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{selector}(method, options = {}) # def text_field(method, options = {}) @template.send("label", @object_name, method) + @template.send( #{selector.inspect}, @object_name, method, objectify_options(options)) end RUBY_EVAL end end
咱們能夠這樣用
<%= form_for(@company, builder: LabellingFormBuilder) do |f| %> <%= f.text_field :name %> <%= f.submit %> <% end %>
將會生成
<form class="new_company" id="new_company" action="/companies" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="EeUl+Px6CvNhgs1nNucJfFiIYEc2zbsNDLzTwfxXcVxDF/JdRevVx6O0AVJhFIMKxelwjlL2A0xB8EXC0JLScg=="> <label for="company_name">Name</label><input type="text" name="company[name]" id="company_name"> <input type="submit" name="commit" value="Create Company"> </form>