FactoryGirl 和 RSpec:为规格创建一条记录,要求 nested_attributes
FactoryGirl and RSpec: create a record with required nested_attributes for specs
我有一个模型 contact
has_many :locations, through: :relationships
,还有 has_many :teams, through: :contacts_teams
。
联系人 必须 具有关联的 team
和 location
才能通过验证。换句话说:一个新的 contact
必须有一个关联的 relationship
记录和一个关联的 contacts_team
记录。以下是型号:
#models/contact.rb
class Contact < ActiveRecord::Base
has_many :contacts_teams
has_many :teams, through: :contacts
has_many :relationships, dependent: :destroy
has_many :locations, through: :relationships
accepts_nested_attributes_for :contacts_teams, allow_destroy: true
# upon create, validate that at least one associated team and one associated location exist
validate :at_least_one_contacts_team
validate :at_least_one_relationship
private
def at_least_one_contacts_team
return errors.add :base, "Must have at least one Team" unless contacts_teams.length > 0
end
def at_least_one_relationship
return errors.add :base, "Must have at least one Location" unless relationships.length > 0
end
end
#models/contacts_team.rb
class ContactsTeam < ActiveRecord::Base
belongs_to :contact
belongs_to :team
end
#models/team.rb
class Team < ActiveRecord::Base
has_many :contacts_teams
has_many :contacts, through: :contacts_teams
end
#models/relationship.rb
class Relationship < ActiveRecord::Base
belongs_to :contact
belongs_to :location
end
#models/location.rb
class Location < ActiveRecord::Base
has_many :relationships
has_many :contacts, through: :relationships
end
用于测试:使用 factory_girl 我想创建一个能够成功创建 contact
记录的 contact
工厂。由于每个 contact
记录都需要关联的 contacts_team
记录和 relationship
记录:当我创建 contact
记录时,也应该创建这些记录。同样:contacts_team
记录应该有一个现有的 team
关联,relation
记录应该有一个现有的 location
关联。所以基本上它应该创建一个 location
和一个 team
记录。
如何创建与工厂的联系记录,这实际上创建了关联的 contacts_team
记录和 relationship
记录?
这是我目前的工厂:
FactoryGirl.define do
factory :contact do
first_name "Homer"
last_name "Simpson"
title "Nuclear Saftey Inspector"
end
end
FactoryGirl.define do
factory :contacts_team do
end
end
FactoryGirl.define do
factory :team do
name "Safety Inspection Team"
end
end
FactoryGirl.define do
factory :relationship do
end
end
FactoryGirl.define do
factory :location do
name "Safety Location"
end
end
如果 difficult/not 可以用 factory_girl 做到这一点:我怎样才能直接用 rspec 做到这一点?问题是我无法创建 contacts_team
记录或 relationship
记录,因为它关联的 contact
尚不存在!而且我无法创建 contact
记录,因为关联的 contacts_team
记录或 relationship
记录尚不存在。看来我被困住了,但必须有一种不马虎的方法来做到这一点。
我上周刚有类似的需求。
在你这个工厂的最后,你可以打电话给下一个工厂,然后他们就会关联起来。例如:
/spec/factories/contacts.rb
FactoryGirl.define do
factory :contact do |c|
first_name "Homer"
last_name "Simpson"
title "Nuclear Saftey Inspector"
# now, call the other two factories
relationship
contacts_team
end
factory :contacts_team do
# call the team factory
team
end
factory :relationship do
# call the location factory
location
end
# define the team and location factories...
end
现在,在 /spec/controllers/contacts_controller_spec.rb
contact = FactoryGirl.create(:contact)
您可以只使用 factory girl 创建一个联系人,即使您只需要一个位置,例如,因为所有内容都会立即生成。
备选方案 (rspec)
不要"chain"你的工厂,而是在/spec/controllers/contacts_controller_spec.rb
contact = FactoryGirl.create(:contact)
# use .create_list(model, number, parent) to make children of a specific parent
contacts_team = FactoryGirl.create_list(:contacts_team, 3, :contact => contact)
relationship = FactoryGirl.create_list(:relationship, 3, :contact => contact)
team = FactoryGirl.create_list(:team, 3, :contacts_team => contacts_team)
location = FactoryGirl.create_list(:location, 3, :relationship => relationship)
这将创建一个联系人,有 3 个 contact_teams(3 个团队)和 3 个关系(3 个位置)
希望这可以帮助您找出正确的模式来制作您的测试数据:)
基本上,您可以通过多种方式进行。但是经常被建议的一种方法是使用 FactoryGirl after(:create)
或 after(:build)
。在您的情况下,如果您拥有所有型号的工厂,您可以轻松调用:
after(:create) do |team, evaluator|
create_list(:contact_team, 5, team: team)
end
根据文档,after(:create) 产生团队和评估器,它存储来自工厂的所有值,包括瞬态属性
这将为您创建 5 个 contact_teams 与团队相关联的人。对于每个工厂,如果您像这样定义所有关系,您将定义完整的关联。另一种方法是遵循 Noam 的建议,这也很好,但有其自身的局限性。
您可以在此处找到更多信息:FactoryGirl Associations
答案在这里。我们需要构建关联记录(contacts_team
记录和 relationship
记录),然后我们将所有记录同时保存到数据库(就像 [=25 如何保存嵌套属性一样) =]):
#factories/contact.rb
FactoryGirl.define do
factory :contact do
first_name "Homer"
last_name "Simpson"
title "Nuclear Saftey Inspector"
agency
contacts_teams {build_list :contacts_team, 1 }
relationships {build_list :relationship, 1 }
end
end
#factories/contacts_teams.rb
FactoryGirl.define do
factory :contacts_team do
team
end
end
#factories/teams.rb
FactoryGirl.define do
factory :team do
name "Safety Inspection Team"
end
end
#factories/relationships.rb
FactoryGirl.define do
factory :relationship do
location
end
end
#factories/locations.rb
FactoryGirl.define do
factory :location do
name "Safety Location"
end
end
那么你需要做的就是:
create(:contact)
然后它同时创建了一个 contact
记录、一个 team
记录、一个 location
记录、关联的 contacts_team
记录和关联的 relationship
记录。
我有一个模型 contact
has_many :locations, through: :relationships
,还有 has_many :teams, through: :contacts_teams
。
联系人 必须 具有关联的 team
和 location
才能通过验证。换句话说:一个新的 contact
必须有一个关联的 relationship
记录和一个关联的 contacts_team
记录。以下是型号:
#models/contact.rb
class Contact < ActiveRecord::Base
has_many :contacts_teams
has_many :teams, through: :contacts
has_many :relationships, dependent: :destroy
has_many :locations, through: :relationships
accepts_nested_attributes_for :contacts_teams, allow_destroy: true
# upon create, validate that at least one associated team and one associated location exist
validate :at_least_one_contacts_team
validate :at_least_one_relationship
private
def at_least_one_contacts_team
return errors.add :base, "Must have at least one Team" unless contacts_teams.length > 0
end
def at_least_one_relationship
return errors.add :base, "Must have at least one Location" unless relationships.length > 0
end
end
#models/contacts_team.rb
class ContactsTeam < ActiveRecord::Base
belongs_to :contact
belongs_to :team
end
#models/team.rb
class Team < ActiveRecord::Base
has_many :contacts_teams
has_many :contacts, through: :contacts_teams
end
#models/relationship.rb
class Relationship < ActiveRecord::Base
belongs_to :contact
belongs_to :location
end
#models/location.rb
class Location < ActiveRecord::Base
has_many :relationships
has_many :contacts, through: :relationships
end
用于测试:使用 factory_girl 我想创建一个能够成功创建 contact
记录的 contact
工厂。由于每个 contact
记录都需要关联的 contacts_team
记录和 relationship
记录:当我创建 contact
记录时,也应该创建这些记录。同样:contacts_team
记录应该有一个现有的 team
关联,relation
记录应该有一个现有的 location
关联。所以基本上它应该创建一个 location
和一个 team
记录。
如何创建与工厂的联系记录,这实际上创建了关联的 contacts_team
记录和 relationship
记录?
这是我目前的工厂:
FactoryGirl.define do
factory :contact do
first_name "Homer"
last_name "Simpson"
title "Nuclear Saftey Inspector"
end
end
FactoryGirl.define do
factory :contacts_team do
end
end
FactoryGirl.define do
factory :team do
name "Safety Inspection Team"
end
end
FactoryGirl.define do
factory :relationship do
end
end
FactoryGirl.define do
factory :location do
name "Safety Location"
end
end
如果 difficult/not 可以用 factory_girl 做到这一点:我怎样才能直接用 rspec 做到这一点?问题是我无法创建 contacts_team
记录或 relationship
记录,因为它关联的 contact
尚不存在!而且我无法创建 contact
记录,因为关联的 contacts_team
记录或 relationship
记录尚不存在。看来我被困住了,但必须有一种不马虎的方法来做到这一点。
我上周刚有类似的需求。
在你这个工厂的最后,你可以打电话给下一个工厂,然后他们就会关联起来。例如:
/spec/factories/contacts.rb
FactoryGirl.define do
factory :contact do |c|
first_name "Homer"
last_name "Simpson"
title "Nuclear Saftey Inspector"
# now, call the other two factories
relationship
contacts_team
end
factory :contacts_team do
# call the team factory
team
end
factory :relationship do
# call the location factory
location
end
# define the team and location factories...
end
现在,在 /spec/controllers/contacts_controller_spec.rb
contact = FactoryGirl.create(:contact)
您可以只使用 factory girl 创建一个联系人,即使您只需要一个位置,例如,因为所有内容都会立即生成。
备选方案 (rspec)
不要"chain"你的工厂,而是在/spec/controllers/contacts_controller_spec.rb
contact = FactoryGirl.create(:contact)
# use .create_list(model, number, parent) to make children of a specific parent
contacts_team = FactoryGirl.create_list(:contacts_team, 3, :contact => contact)
relationship = FactoryGirl.create_list(:relationship, 3, :contact => contact)
team = FactoryGirl.create_list(:team, 3, :contacts_team => contacts_team)
location = FactoryGirl.create_list(:location, 3, :relationship => relationship)
这将创建一个联系人,有 3 个 contact_teams(3 个团队)和 3 个关系(3 个位置)
希望这可以帮助您找出正确的模式来制作您的测试数据:)
基本上,您可以通过多种方式进行。但是经常被建议的一种方法是使用 FactoryGirl after(:create)
或 after(:build)
。在您的情况下,如果您拥有所有型号的工厂,您可以轻松调用:
after(:create) do |team, evaluator|
create_list(:contact_team, 5, team: team)
end
根据文档,after(:create) 产生团队和评估器,它存储来自工厂的所有值,包括瞬态属性
这将为您创建 5 个 contact_teams 与团队相关联的人。对于每个工厂,如果您像这样定义所有关系,您将定义完整的关联。另一种方法是遵循 Noam 的建议,这也很好,但有其自身的局限性。 您可以在此处找到更多信息:FactoryGirl Associations
答案在这里。我们需要构建关联记录(contacts_team
记录和 relationship
记录),然后我们将所有记录同时保存到数据库(就像 [=25 如何保存嵌套属性一样) =]):
#factories/contact.rb
FactoryGirl.define do
factory :contact do
first_name "Homer"
last_name "Simpson"
title "Nuclear Saftey Inspector"
agency
contacts_teams {build_list :contacts_team, 1 }
relationships {build_list :relationship, 1 }
end
end
#factories/contacts_teams.rb
FactoryGirl.define do
factory :contacts_team do
team
end
end
#factories/teams.rb
FactoryGirl.define do
factory :team do
name "Safety Inspection Team"
end
end
#factories/relationships.rb
FactoryGirl.define do
factory :relationship do
location
end
end
#factories/locations.rb
FactoryGirl.define do
factory :location do
name "Safety Location"
end
end
那么你需要做的就是:
create(:contact)
然后它同时创建了一个 contact
记录、一个 team
记录、一个 location
记录、关联的 contacts_team
记录和关联的 relationship
记录。