2012-01-11 26 views
18

Guardian、Student、Relationship、RelationshipType、Schoolの5つのモデルがあります。それらの間に私はこれらの団体を持っていますファクトリー内の2つの関連付けを取得して別の関連付けを行う

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を書いてみたいと思います。すべての関係には保護者と学生がいなければなりません。これら2つは同じ学校に属していなければなりません。保護者工場には学校との関連があり、学生工場も同様です。私はそれらを同じ学校に建設することができませんでした。に、

undefined method `school' for #<FactoryGirl::Declaration::Implicit:0x0000010098af98> (NoMethodError) 

私が欲しいものを行うにはどのような方法があります:私はこのファクトリを使用して関係を構築しようとすると、これは、次のエラーが発生し

FactoryGirl.define do 

    factory :relationship do 
    association :guardian 
    association :student, :school => self.guardian.school 
    relationship_type RelationshipType.first 
    end 

end 

:私は、次のコードを持っています既に作成された保護者と生徒を工場に渡すことに頼らなくても、保護者と学生を同じ学校に所属させることができます(これは目的ではありません)。

+0

これはエラーと関係がありますが、私の編集前の2番目のRelationshipクラス宣言としてSchoolクラスが書かれているかどうかはわかりません。 – PinnyM

答えて

7

私は、これは動作するはずだと思う:

FactoryGirl.define do 
    factory :relationship do 
    association :guardian 
    relationship_type RelationshipType.first 
    after_build do |relationship| 
     relationship.student = Factory(:student, :school => relationship.guardian.school) 
    end 
    end 
end 
+3

本当にこれを行う良い方法があるはずです... – Ajedi32

9

この答えが「工場の少女共有協会」のGoogleで最初の結果であるとsantuxusからの答えは本当に私を助け:)

ここで更新があります場合のファクトリー・ガールの最新バージョンからの構文とその両端の誰つまずく:

FactoryGirl.define do 
    factory :relationship do 
    guardian 
    relationship_type RelationshipType.first 

    after(:build) do |relationship| 
     relationship.student = FactoryGirl.create(:student, school: relationship.guardian.school) unless relationship.student.present? 
    end 
    end 
end 

unless句はを防止しますFactoryGirl.create(:relationship, student: foo)で工場に渡された場合はが置き換えられません。

2

この関連付けを記述するのにきれいな方法があります。回答はthis github issueから得ました。

FactoryGirl.define do 
    factory :relationship do 
    association :guardian 
    student { build(:student, school: relationship.guardian.school) } 
    relationship_type RelationshipType.first 
    end 
end 
+0

その問題に基づいて、その行は 'student {build(:student、school:guardian.school)}'でなければなりません( 'relationship'は省略されています) –

1

これは本当にあなたが求めている答えではありませんが、この関連付けを作成することの困難は、テーブルのデザインを調整する必要があるかもしれないことを示唆しているようです。

What if the user changes school?という質問には、StudentGuardianの両方の学校を更新する必要があります。そうでない場合、モデルの同期がとれなくなります。

私は、学生、保護者、および学校の​​すべてが一緒に関係を持っていることを伝えました。生徒が学校を変更すると、新しい学校の新しいRelationshipが作成されます。良い副作用として、これは、学生が教育されている場所の歴史を可能にします。

belongs_toの関連付けはStudentGuardianから削除され、代わりにRelationshipに移動されました。

工場は、このように見えるように変更することができます。

factory :relationship do 
    school 
    student 
    guardian 
    relationship_type 
end 

これは、次の方法で使用できます。

# use the default relationship which creates the default associations 
relationship = Factory.create :relationship 
school = relationship.school 
student = relationship.student 
guardian = relationship.guardian 

# create a relationship with a guardian that has two charges at the same school 
school = Factory.create :school, name: 'Custom school' 
guardian = Factory.create :guardian 
relation1 = Factory.create :relationship, school: school, guardian: guardian 
relation2 = Factory.create :relationship, school: school, guardian: guardian 
student1 = relation1.student 
student2 = relation2.student 
0

私はこのケースでtransient & dependent属性を使用したいです:

FactoryGirl.define do 
    factory :relationship do 
    transient do 
     school { create(:school) } 
     # now you can even override the school if you want! 
    end 

    guardian { create(:guardian, school: school) } 
    student { create(:student, school: school) } 
    relationship_type RelationshipType.first 
    end 
end 

用途:

relationship = FactoryGirl.create(:relationship) 

relationship.guardian.school == relationship.student.school 
# => true 

そして、あなたも、あなたがしたい場合は、学校を上書きすることができます。nitsasのソリューションに拡張

awesome_school = FactoryGirl.create(:school) 
awesome_relationship = FactoryGirl.create(:relationship, school: awesome_school) 

awesome_relationship.guardian.school == awesome_school 
# => true 
awesome_relationship.student.school == awesome_school 
# => true 
0

を、あなたは@overridesを乱用することができ、保護者や生徒会が上書きされているかどうかを確認するために、および使用保護者/学生からの学校協会。これにより、学校だけでなく、保護者または生徒だけを無効にすることができます。

残念ながら、これはパブリックAPIではなくインスタンス変数に依存しています。将来のアップデートはあなたの工場を非常にうまく破損する可能性があります。

関連する問題