我想更好地理解has_many through:
关联如何在Rails 4.0上运行。
假设我有这些模型:
class Parent
has_many :parent_sons
has_many :sons, through: :parent_sons
end
class Son
has_many :parent_sons
has_many :parents, through: :parent_sons
end
class ParentSon
belongs_to :parent
belongs_to :son
validates :son, presence: true
validates :parent, presence: true
end
现在,如果我进入控制台并创建几个测试对象,通过has_many through:
定义关联父母和儿子,我会得到:
a = Parent.new
b = Son.new
a.sons << b
a.valid?
=> false
# The ParentSon object has a Son but no Parent:
c = a.parent_sons.first
c.son
=> b
c.parent
=> nil
如果我输入
,就会出现同样的行为a.parent_sons.build(son: b)
而不是a.sons << b
。
所以,显然,ParentSon
对象和Son
对象之间已创建了正确的关联,而ParentSon
和Parent
之间没有创建正确的关联。将Son
附加到。
同样,如果我这样做
b.parents << a
我将获得ParentSon
和Parent
之间的关系,但不会获得原始Son
之间的关系。
显然这打破了ParentSon
对象中的验证,因为两个外向关系中的一个总是丢失。
那么,在不破坏此类验证的情况下,使用has_many through:
关联附加现有对象的正确方法是什么?
这种行为也打破了我的rspec测试。以这种方式使用factory_girl
gem:
factory :parent do
after(:create) do |p|
p.sons << FactoryGirl.create(:son)
end
end
通过FactoryGirl.create(:parent)
创建的对象不会因同样的原因通过验证,因为它的ParentSon
对象具有正确的Son
引用但空Parent
。
答案 0 :(得分:1)
我发现在使用has_many through:
时,使用现有Parent
对象正确添加与Son
的关系的唯一方法是完全定义连接对象的详细信息。
例如
a.parent_sons.build(parent: a, son: b)
是正确的方法。对父级create
或build
儿子的任何其他尝试都会导致parent_id
对象中缺少ParentSon
。
通过这种关联,a.sons << b
方法是不可行的。
答案 1 :(得分:0)
我认为您的问题是由您在尚未创建对象时尝试设置关联(即尚未拥有ID)引起的。这是怎么回事?
#make an unsaved (no id) Parent
a = Parent.new
#make an unsaved (no id) Son
b = Son.new
#try to make the association, by building a join table (ParentSon) record.
a.sons << b
#the ParentSon object has neither a parent_id or a son_id, which is making it fail validation
a.valid?
=> false
如果要在尚未创建的对象之间建立关联,可以使用.build
代替。这将在保存父项时保存父项时的关联对象。例如
parent = Parent.new
son = parent.sons.build
parent.save
父亲现在有一个id,儿子有一个id,并且应该建立关联。两者都应该有效。试试吧。