关于一件事,我有点困惑,那就是在控制器中创建了多个“ belongs_to”模型项。
基本上,我在说我们有Person
模型,Person
has_many
Addresses
和accepts_nested_attributes_for :addresses
(假设“地址”只是一个文本字段,以表单的形式,我们最终将拥有一个3个地址)
在“新”控制器中,我通常会看到以下内容:
@person = Person.new
3.times { @person.addresses.build }
然后在“创建”控制器操作中,将接受所有3个字段(使用fields_for
形式),然后进行正常的全部创建。通过类似的东西:
def person_params
params.require(:booking).permit(:name,:email,:age, :addresses_attributes => [:address])
end
它会创建所有3个地址。我不明白它是如何工作的。正在构建3个不同的实例,然后以某种方式Rails只是“知道”如何将它们关联起来?
任何人都可以解释发生了什么事吗?
答案 0 :(得分:1)
当您声明Person模型accepts_nested_attributes_for :addresses
时,您真正要说的是我希望Rails在Person模型上为地址(多个)创建getter和setter实例方法。
这类似于其他关系。例如,如果您在Person上声明has_many:friends关系,则可以调用@person.friends
(getter)或@person.friends.create
(setter)。
视觉效果……
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
当您允许在控制器中使用addresss_attributes时
params.require(:person).permit(:addresses_attributes => [:address])
想起来就像您在创建一个Person时允许调用addresses_attribues
setter方法一样……setter方法接受从表单提交的地址(多个)并将它们与该特定人员相关联。但是,当您调用@ person.addresses时,您会注意到它返回一个ActiveRecord::Associations::CollectionProxy,这一点很重要。
在控制器中,当您说出
@person = Person.new
3.times { @person.addresses.build }
可以想像它是创建一个空的Person以及与该Person关联的3个空地址,只有通过提交表单调用create动作后,这些属性才会填充属性。
编辑:
嵌套属性的主要优点(与常规关联有所不同)是,它允许您使用一种形式来创建/修改父类(在这种情况下为Person),同时创建通过使用fields_for
“我想另一个令人困惑的部分是,rails如何知道此人有3个空地址?”
Rails并不能立即知道...这就是为什么您必须在控制器中显式实例化X个空地址的原因。因此,现在当您调用form.fields_for :addresses
时,只有X量的内存可以存储X量的地址。
答案 1 :(得分:1)
accept_nested_attributes_for :addresses
在您的Person
模型中,定义了has_many :addresses
关联的属性编写器。
现在,当您将表单提交到Rails应用程序时,参数可能看起来类似于以下内容:
"user"=>{"name"=>'John', "email"=>'john@domain.com',"age"=>"25"
addresses_attributes"=>{"0"=>{"address"=>"Street 1"}, "1"=>{"address"=>"Street 2"}, "2"=>{"address"=>"Street 2"}}}
如果仔细查看addresses_attributes
参数,它看起来类似于hash
,并且key
中的每个hash
代表一个address
对象。这就是Rails确切知道必须创建3条address
记录的方式。
如果您想更好地理解这一点,请阅读此rails documentation
已更新:
在new
操作中使用3.times { @person.addresses.build }
预先实例化地址完全不是强制性的
并且硬编码地址数可能不是正确的方法。如果有人要存储5个地址而您的应用程序只允许3个地址怎么办?