开发者

Rails fields_for :child_index option explanation

开发者 https://www.devze.com 2023-01-01 01:26 出处:网络
I have been trying to create a complex form with many nested models, and make it dynamic. Now I found that making a nested model isn\'t difficult with accepts_nested_attributes_for, but making it nest

I have been trying to create a complex form with many nested models, and make it dynamic. Now I found that making a nested model isn't difficult with accepts_nested_attributes_for, but making it nested and dynamic was seemingly impossible if there were multiple nested models.

I came across http://github.com/ryanb/complex-form-examples/blob/master/app/helpers/application_helper.rb which does it very elegantly. Could anyone shed some light on lines 13 and 16?

13 form_builder.object.class.reflect_on_association(method).klass.new

and

16 form_builder.fields_for(method, options[:object], :child_index => "new_#{method}") do 开发者_运维百科|f|

From intuition, line 13 instantiates a new object, but why must it do so many method calls? I couldn't find any documentation for the :child_index option on line 16. When the form is created, a very large number is used as an index for new models, whereas existing models are indexed by their id. How does this work?


options[:object] ||= form_builder.object.class.reflect_on_association(method).klass.new

If the object is not passed as a parameter, it creates a new object of the corresponding class.

form_builder.object gets the main object from the form (project)

form_builder.object.class gets its class (Project)

method is the association name for the Project (:tasks)

reflect_on_association(method) gives AssociationReflection object.

reflect_on_association(method).klass returns the class of the association. (Task)

And, finally, klass.new creates a new instance (Task.new => new task)

It is done this way because the association name is not always just a pluralized class name like in this case (Task - :tasks), but it is necessary to get the class object to create new instance of it.

form_builder.fields_for(method, options[:object], :child_index => "new_#{method}") do |f|

:child_index option allows you to specify the index of particular object:

project[tasks_attributes][:child_index][field_name]

It is set to `"new_#{method}" by Rails, but is then replaced by javascript (application.js):

function insert_fields(link, method, content) {
  var new_id = new Date().getTime();
  var regexp = new RegExp("new_" + method, "g")
  $(link).up().insert({
    before: content.replace(regexp, new_id)
  });
}

Index is set to a large number just not to conflict with existing items. They are not indexed by id by the way, just from 0 to count-1

0

精彩评论

暂无评论...
验证码 换一张
取 消