如何使用has_many关联在FactoryGirl中设置工厂

Ton*_*nys 85 rspec has-many-through ruby-on-rails-3.1 factory-bot

有人能告诉我,如果我只是以错误的方式进行设置吗?

我有以下具有has_many.through关联的模型:

class Listing < ActiveRecord::Base
  attr_accessible ... 

  has_many :listing_features
  has_many :features, :through => :listing_features

  validates_presence_of ...
  ...  
end


class Feature < ActiveRecord::Base
  attr_accessible ...

  validates_presence_of ...
  validates_uniqueness_of ...

  has_many :listing_features
  has_many :listings, :through => :listing_features
end


class ListingFeature < ActiveRecord::Base
  attr_accessible :feature_id, :listing_id

  belongs_to :feature  
  belongs_to :listing
end
Run Code Online (Sandbox Code Playgroud)

我正在使用Rails 3.1.rc4,FactoryGirl 2.0.2,factory_girl_rails 1.1.0和rspec.这是我对:listing工厂的基本rspec rspec健全性检查:

it "creates a valid listing from factory" do
  Factory(:listing).should be_valid
end
Run Code Online (Sandbox Code Playgroud)

这是工厂(:上市)

FactoryGirl.define do
  factory :listing do
    headline    'headline'
    home_desc   'this is the home description'
    association :user, :factory => :user
    association :layout, :factory => :layout
    association :features, :factory => :feature
  end
end
Run Code Online (Sandbox Code Playgroud)

:listing_feature:feature工厂也同样设置.
如果该association :features行被注释掉,那么我的所有测试都会通过.
几时

association :features, :factory => :feature
Run Code Online (Sandbox Code Playgroud)

错误消息是 undefined method 'each' for #<Feature> 我认为对我有意义的因为因为listing.features返回一个数组.所以我改成了

association :features, [:factory => :feature]
Run Code Online (Sandbox Code Playgroud)

我现在得到的错误是以ArgumentError: Not registered: features 这种方式生成工厂对象或者我缺少什么是不明智的?非常感谢任何和所有的输入!

Jel*_*Cat 103

或者,您可以使用块并跳过association关键字.这使得可以在不保存到数据库的情况下构建对象(否则,即使您使用build函数代替,has_many关联也会将您的记录保存到数据库create).

FactoryGirl.define do
  factory :listing_with_features, :parent => :listing do |listing|
    features { build_list :feature, 3 }
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 这是猫的喵喵叫."构建"和"创建"的能力使其成为最通用的模式.然后在测试`accepts_nested_attributes_for`的控制器操作时,使用此自定义FG构建策略https://gist.github.com/Bartuz/74ee5834a36803d712b7来"post nested_attributes_for". (5认同)
  • upvoted,比IMO接受的答案更具可读性和多样性 (4认同)

win*_*red 55

创建这些类型的关联需要使用FactoryGirl的回调.

这里有一套完美的例子.

https://thoughtbot.com/blog/aint-no-calla-back-girl

把它带回家就是你的榜样.

Factory.define :listing_with_features, :parent => :listing do |listing|
  listing.after_create { |l| Factory(:feature, :listing => l)  }
  #or some for loop to generate X features
end
Run Code Online (Sandbox Code Playgroud)


eho*_*ann 22

你可以使用trait:

FactoryGirl.define do
  factory :listing do
    ...

    trait :with_features do
      features { build_list :feature, 3 }
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

callback,如果您需要数据库创建:

...

trait :with_features do
  after(:create) do |listing|
    create_list(:feature, 3, listing: listing)
  end
end
Run Code Online (Sandbox Code Playgroud)

在您的规格中使用,如下所示:

let(:listing) { create(:listing, :with_features) }
Run Code Online (Sandbox Code Playgroud)

这将删除工厂中的重复并更可重用.

https://robots.thoughtbot.com/remove-duplication-with-factorygirls-traits


Dav*_*Sag 20

我尝试了几种不同的方法,这是对我来说最可靠的方法(适合你的情况)

FactoryGirl.define do
  factory :user do
    # some details
  end

  factory :layout do
    # some details
  end

  factory :feature do
    # some details
  end

  factory :listing do
    headline    'headline'
    home_desc   'this is the home description'
    association :user, factory: :user
    association :layout, factory: :layout
    after(:create) do |liztng|
      FactoryGirl.create_list(:feature, 1, listing: liztng)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)


thi*_*ign 6

从 FactoryBot v5 开始,协会保留了构建策略。关联是解决这个问题的最佳方法,文档中有很好的例子

FactoryBot.define do
  factory :post do
    title { "Through the Looking Glass" }
    user
  end

  factory :user do
    name { "Taylor Kim" }

    factory :user_with_posts do
      posts { [association(:post)] }
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

或者控制计数:

    transient do
      posts_count { 5 }
    end

    posts do
      Array.new(posts_count) { association(:post) }
    end
Run Code Online (Sandbox Code Playgroud)