[英]Rails has_many/accepts_nested_attributes_for Create confusion?
I'm a bit confused when it comes to one thing and that's creating MULTIPLE "belongs_to" model items in the controller. 当涉及到一件事时,我有点困惑,那就是在控制器中创建多个“ belongs_to”模型项。
Basically, I've seen it where say we have a Person
model, and that Person
has_many
Addresses
and also accepts_nested_attributes_for :addresses
基本上,我在说我们有一个
Person
模型的地方看到过它,并且Person
has_many
Addresses
并且accepts_nested_attributes_for :addresses
(Let's pretend the Address is just a single text field, and let's say in the form we are going to end up having 3 addresses for a person) (让我们假装“地址”只是一个文本字段,以表单的形式,我们最终将为一个人拥有3个地址)
In the "new" controller I will typically see something like: 在“新”控制器中,我通常会看到类似以下内容的内容:
@person = Person.new
3.times { @person.addresses.build }
Then in the "create" controller action it'll go through and do the normal create all while accepting all 3 fields (using fields_for
form) of addresses. 然后,在“创建”控制器操作中,将接受所有3个地址字段(使用
fields_for
形式),然后进行正常的全部创建。 via something like: 通过类似的东西:
def person_params
params.require(:booking).permit(:name,:email,:age, :addresses_attributes => [:address])
end
And it'll create all 3 addresses just fine. 它将创建所有3个地址。 I don't understand how it works.
我不明白它是如何工作的。 Were building 3 different instances and then somehow rails just "knows" how to associate them?
正在构建3个不同的实例,然后以某种方式Rails只是“知道”如何将它们关联起来?
Can anyone explain what's going on? 谁能解释这是怎么回事?
When you declare that a Person model accepts_nested_attributes_for :addresses
, all you are really saying is I want Rails to create getter and setter instance methods on the Person model for addresses (plural). 当您声明一个Person模型
accepts_nested_attributes_for :addresses
,您真正要说的是我希望Rails在Person模型上为地址(复数)创建getter和setter实例方法。 This is similar to other relationships. 这类似于其他关系。 For instance, if you declare a has_many :friends relationship on Person, you would be able to call
@person.friends
(the getter) or @person.friends.create
(the setter). 例如,如果您在Person上声明has_many:friends关系,则可以调用
@person.friends
(获取程序)或@person.friends.create
(设置程序)。 Heres a visual... 这是视觉效果...
class Person < ActiveRecord::Base
# this is the getter method
def addresses
# I can retrieve all of the associated addresses for a particular person
end
# this is the setter method
def addresses_attributes=(attributes)
# I can take in any number of addresses and assoicate them to a particular person
end
end
When you permit addresses_attributes in the controller 当您允许在控制器中使用addresses_attributes时
params.require(:person).permit(:addresses_attributes => [:address])
Think of it like you are allowing the addresses_attribues
setter method to be called when creating a Person...the setter method takes in the addresses (plural) submitted from the form and associates them with that particular person. 想想这就像你让
addresses_attribues
setter方法创建一个人的时候,被称为... setter方法接受来自表单提交的地址(复数),并将它们与特定的人相关联。 But, when you call @person.addresses, you'll notice that it returns an ActiveRecord::Associations::CollectionProxy , which is important to understand. 但是,当您调用@ person.addresses时,您会注意到它返回一个ActiveRecord :: Associations :: CollectionProxy ,这对理解很重要。
In the controller, when you say 在控制器中,当您说
@person = Person.new
3.times { @person.addresses.build }
Think of it like creating an empty Person and 3 empty addresses associated with that person, which will only be populated with attributes once the create action is called by submitting the form. 可以将其想象为创建一个空的Person以及与该Person关联的3个空地址,只有在通过提交表单调用create动作后,这些属性才会填充属性。
EDIT: 编辑:
The main benefit of nested attributes (and it's difference from a normal association) is that it allows you to use a single form to create/modify the parent class (in this case, the Person), and at the same time create/modify it's associated attributes (in this case, addresses) through the use of fields_for
嵌套属性的主要优点(与常规关联有所不同)是,它允许您使用一种形式来创建/修改父类(在本例中为Person),同时创建/修改父类。通过使用
fields_for
关联属性(在本例中为地址)
"I guess the other confusing part is how rails knows that the Person has 3 empty addresses?" “我想另一个令人困惑的部分是,rails如何知道此人有3个空地址?”
Rails doesn't know right off the bat...which is why you have to explicitly instantiate X amount of empty addresses in the controller. Rails马上就不知道了。这就是为什么您必须在控制器中显式实例化X个空地址的原因。 So now when you call
form.fields_for :addresses
there is only X amount of memory to store X amount of addresses. 因此,现在当您调用
form.fields_for :addresses
,只有X数量的内存可以存储X数量的地址。
accept_nested_attributes_for :addresses
in your Person
model defines an attributes writer for the has_many :addresses
association. Person
模型中的accept_nested_attributes_for :addresses
定义了has_many :addresses
关联的属性accept_nested_attributes_for :addresses
。
Now when you submit your form to the Rails application, The params might look something similar to this: 现在,当您将表单提交到Rails应用程序时,参数可能看起来类似于以下内容:
"user"=>{"name"=>'John', "email"=>'john@domain.com',"age"=>"25"
addresses_attributes"=>{"0"=>{"address"=>"Street 1"}, "1"=>{"address"=>"Street 2"}, "2"=>{"address"=>"Street 2"}}}
If you take a close look at the addresses_attributes
param, it looks similar to a hash
and each key
in that hash
represents an address
object. 如果你把在密切关注
addresses_attributes
PARAM,它类似于一个hash
和每个key
在hash
表示address
的对象。 That is how Rails will exactly know that it has to create 3 address
records. 这就是Rails确切知道必须创建3条
address
记录的方式。
Also if you would like to understand this better, go through this rails documentation 另外,如果您想更好地理解这一点,请阅读此Rails文档
Updated: 更新:
It is not at all compulsory to instantiate the addresses in advance in the new
action with 3.times { @person.addresses.build }
在
new
动作中使用3.times { @person.addresses.build }
预先实例化地址完全不是强制性的。
And hardcoding number of addresses might not be a right way to do it. 硬编码地址可能不是正确的方法。 What if someone wants to store 5 addresses and your application allows just 3?
如果有人要存储5个地址而您的应用程序只允许3个地址怎么办?
So probably you can use Jquery and implement this in a much better way. 因此,您可能可以使用Jquery并以更好的方式实现它。 Or even you could use cocoon gem.
或者甚至可以使用茧宝石。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.