FactoryGirl和多态关联

Fee*_*ech 66 ruby-on-rails factory-bot

该设计

我有一个通过多态关联属于配置文件的用户模型.我选择这个设计的原因可以在这里找到.总而言之,该应用程序的许多用户具有真正不同的配置文件.

class User < ActiveRecord::Base
  belongs_to :profile, :dependent => :destroy, :polymorphic => true
end
Run Code Online (Sandbox Code Playgroud)
class Artist < ActiveRecord::Base
  has_one :user, :as => :profile
end
Run Code Online (Sandbox Code Playgroud)
class Musician < ActiveRecord::Base
  has_one :user, :as => :profile
end
Run Code Online (Sandbox Code Playgroud)

选择这个设计后,我很难做出好的测试.使用FactoryGirl和RSpec,我不确定如何以最有效的方式声明关联.

第一次尝试

factories.rb

Factory.define :user do |f|
  # ... attributes on the user
  # this creates a dependency on the artist factory
  f.association :profile, :factory => :artist 
end

Factory.define :artist do |a|
  # ... attributes for the artist profile
end
Run Code Online (Sandbox Code Playgroud)

user_spec.rb

it "should destroy a users profile when the user is destroyed" do
  # using the class Artist seems wrong to me, what if I change my factories?
  user = Factory(:user)
  profile = user.profile
  lambda { 
    user.destroy
  }.should change(Artist, :count).by(-1)
end
Run Code Online (Sandbox Code Playgroud)

评论/其他想法

正如用户规范中的评论所述,使用Artist似乎很脆弱.如果我的工厂将来发生变化怎么办?

也许我应该使用factory_girl回调并定义"艺术家用户"和"音乐家用户"?所有输入都表示赞赏.

ver*_*as1 146

虽然有一个公认的答案,但这里有一些使用新语法的代码对我有用,可能对其他人有用.

投机/ factories.rb

FactoryGirl.define do

  factory :musical_user, class: "User" do
    association :profile, factory: :musician
    #attributes for user
  end

  factory :artist_user, class: "User" do
    association :profile, factory: :artist
    #attributes for user
  end

  factory :artist do
    #attributes for artist
  end

  factory :musician do
    #attributes for musician
  end
end
Run Code Online (Sandbox Code Playgroud)

规格/型号/ artist_spec.rb

before(:each) do
  @artist = FactoryGirl.create(:artist_user)
end
Run Code Online (Sandbox Code Playgroud)

这将创建艺术家实例以及用户实例.所以你可以打电话:

@artist.profile
Run Code Online (Sandbox Code Playgroud)

获取Artist实例.


kub*_*oon 36

使用这样的特征;

FactoryGirl.define do
    factory :user do
        # attributes_for user
        trait :artist do
            association :profile, factory: :artist
        end
        trait :musician do
            association :profile, factory: :musician
        end
    end
end
Run Code Online (Sandbox Code Playgroud)

现在你可以通过获取用户实例了 FactoryGirl.create(:user, :artist)


mem*_*per 11

Factory_Girl回调会让生活变得更轻松.这样的事怎么样?

Factory.define :user do |user|
  #attributes for user
end

Factory.define :artist do |artist|
  #attributes for artist
  artist.after_create {|a| Factory(:user, :profile => a)}
end

Factory.define :musician do |musician|
  #attributes for musician
  musician.after_create {|m| Factory(:user, :profile => m)}
end
Run Code Online (Sandbox Code Playgroud)


Kin*_*mah 5

您还可以使用嵌套工厂(继承)解决此问题,这样您可以为每个类创建一个基本工厂,然后嵌套从该基本父级继承的工厂。

FactoryGirl.define do
    factory :user do
        # attributes_for user
        factory :artist_profile do
            association :profile, factory: :artist
        end
        factory :musician_profile do
            association :profile, factory: :musician
        end
    end
end
Run Code Online (Sandbox Code Playgroud)

现在,您可以访问嵌套工厂,如下所示:

artist_profile = create(:artist_profile)
musician_profile = create(:musician_profile)
Run Code Online (Sandbox Code Playgroud)

希望这对某人有帮助。

  • 嵌套的工厂可能变得很困难。这里的性格是可取的。如果您需要工厂作为子类,请创建定义父项的子工厂。 (2认同)