让工厂内的两个关联共享另一个关联
我有这 5 个模型:监护人、学生、关系、关系类型和学校。在它们之间,我有这些关联
class Guardian < ActiveRecord::Base
belongs_to :school
has_many :relationships, :dependent => :destroy
has_many :students, :through => :relationships
end
class Student < ActiveRecord::Base
belongs_to :school
has_many :relationships, :dependent => :destroy
has_many :guardians, :through => :relationships
end
class Relationship < ActiveRecord::Base
belongs_to :student
belongs_to :guardian
belongs_to :relationship_type
end
class School < ActiveRecord::Base
has_many :guardians, :dependent => :destroy
has_many :students, :dependent => :destroy
end
class RelationshipType < ActiveRecord::Base
has_many :relationships
end
,我想编写一个定义关系的 FactoryGirl 。每段关系都必须有监护人和学生。这两个人必须属于同一所学校。监护人工厂与学校有关联,学生工厂也有关联。我一直无法让它们建在同一所学校。我有以下代码:
FactoryGirl.define do
factory :relationship do
association :guardian
association :student, :school => self.guardian.school
relationship_type RelationshipType.first
end
end
当我尝试使用此工厂建立关系时,会导致以下错误:
undefined method `school' for #<FactoryGirl::Declaration::Implicit:0x0000010098af98> (NoMethodError)
有没有办法做我想做的事,使监护人和学生属于同一所学校,而不必诉诸于将已经创建的监护人和学生传递到工厂(这不是其目的)?
I've got these 5 models: Guardian, Student, Relationship, RelationshipType and School. Between them, I've got these associations
class Guardian < ActiveRecord::Base
belongs_to :school
has_many :relationships, :dependent => :destroy
has_many :students, :through => :relationships
end
class Student < ActiveRecord::Base
belongs_to :school
has_many :relationships, :dependent => :destroy
has_many :guardians, :through => :relationships
end
class Relationship < ActiveRecord::Base
belongs_to :student
belongs_to :guardian
belongs_to :relationship_type
end
class School < ActiveRecord::Base
has_many :guardians, :dependent => :destroy
has_many :students, :dependent => :destroy
end
class RelationshipType < ActiveRecord::Base
has_many :relationships
end
I want to write a FactoryGirl which defines a relationship. Every relationship must have a guardian and a student. These two must belong to the same school. The guardian factory has an association with school, and so does the student factory. I've been unable to get them to be built in the same school. I've got the following code:
FactoryGirl.define do
factory :relationship do
association :guardian
association :student, :school => self.guardian.school
relationship_type RelationshipType.first
end
end
This results in the following error when I try to build a relationship using this factory:
undefined method `school' for #<FactoryGirl::Declaration::Implicit:0x0000010098af98> (NoMethodError)
Is there any way to do what I want, to make the guardian and the student belong to the same school without having to resort to passing already created guardians and students to the factory (which is not its purpose)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这个答案是 Google 上关于“工厂女孩共享关联”的第一个结果,来自 santuxus 的答案确实帮助了我:)
这是最新版本的工厂女孩的语法更新,以防其他人偶然发现它:
unless
子句会阻止student
在使用FactoryGirl.create(:relationship, Student: foo)
传递到工厂时被替换。This answer is the first result on Google for 'factory girl shared association' and the answer from santuxus really helped me out :)
Here's an update with the syntax from the latest version of Factory Girl in case anyone else stumbles across it:
The
unless
clause preventsstudent
from being replaced if it's been passed into the factory withFactoryGirl.create(:relationship, student: foo)
.我认为这应该有效:
I think this should work:
有更清晰的方式来编写这个关联。答案来自此 github 问题。
There is cleaner way to write this association. Answer got from this github issue.
扩展 nitsas 的解决方案,您可以滥用
@overrides
来检查监护人或学生协会是否已被覆盖,并使用监护人/学生的学校协会。这使您不仅可以凌驾于学校之上,还可以凌驾于监护人或学生之上。不幸的是,这依赖于实例变量,而不是公共 API。未来的更新很可能会破坏你的工厂。
Extending on nitsas' solution, you can abuse
@overrides
to check whether the guardian or student association have been overridden, and use the school association from the guardian/student. This allows you to override not only the school, but also just the guardian or just the student.Unfortunately, this relies on instance variables, not public API. Future updates could very well break your factories.
这并不是您真正正在寻求的答案,但似乎创建此关联的困难表明表格设计可能需要调整。
提出问题
如果用户改变学校怎么办?
,Student
和Guardian
上的学校都需要更新,否则模型会得到不同步。我提出学生、监护人、学校三者是一体的。如果学生更换学校,则会为新学校创建新的
关系
。作为一个很好的副作用,这使得学生所受教育的历史记录得以存在。belongs_to
关联将从Student
和Guardian
中删除,并移至Relationship
。然后可以将工厂更改为如下所示:
然后可以通过以下方式使用它:
This isn't really an answer you are seeking, but it seems that the difficulty in creating this association is suggesting that the table design may need to be adjusted.
Asking the question
What if the user changes school?
, the school on both theStudent
andGuardian
needs to be updated, otherwise, the models get out of sync.I put forward that a student, a guardian, and a school, all have a relationship together. If a student changes school, a new
Relationship
is created for the new school. As a nice side effect this enables a history to exist of where the student has been schooled.The
belongs_to
associations would be removed fromStudent
andGuardian
, and moved toRelationship
instead.The factory can then be changed to look like this:
This can then be used in the following ways:
我会使用 transient &在这种情况下,依赖属性:
用法:
而你如果您愿意,甚至可以覆盖学校:
I'd use transient & dependent attributes in this case:
Usage:
And you can even override the school if you want: