/ / FactoryGirl и полиморфни асоциации - ruby-on-rails, фабричен бот

FactoryGirl и полиморфни асоциации - рубинки на релси, фабрика-ботове

Дизайнът

Имам потребителски модел, който принадлежи към профил чрез полиморфна асоциация. Причината, поради която избрах този дизайн, може да бъде намерена тук, За да обобщим, има много потребители на приложението, които имат наистина различни профили.

class User < ActiveRecord::Base
belongs_to :profile, :dependent => :destroy, :polymorphic => true
end

class Artist < ActiveRecord::Base
has_one :user, :as => :profile
end

class Musician < ActiveRecord::Base
has_one :user, :as => :profile
end

След избора на този дизайн, трудно ми идва с добри тестове. С помощта на 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

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

Коментари / други мисли

Както бе споменато в коментарите в спецификациите на потребителя, използването на Artist изглежда крехко. Ами ако моите фабрики се променят в бъдеще?

Може би трябва да използвам обратните извиквания на фабриката и дефиниране на "потребител на изпълнител" и "потребител на музикант"? Всички данни са оценени.

Отговори:

10 за отговор № 1

Обратните обаждания на 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

141 за отговор № 2

Въпреки че има приет отговор, ето един код, използващ новия синтаксис, който работи за мен и може да бъде полезен на някой друг.

спец / 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

спец / модели / artist_spec.rb

before(:each) do
@artist = FactoryGirl.create(:artist_user)
end

Което ще създаде потребителската инстанция, както и потребителския потребителски модел. Така че можете да се обадите:

@artist.profile

за да получите копие на изпълнителя.


32 за отговор № 3

Използвайте такива черти;

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

сега можете да получите потребителски потребителски екземпляр от FactoryGirl.create(:user, :artist)


4 за отговор № 4

Можете също така да решите това с помощта на вложени фабрики (наследяване), по този начин ще създадете основен завод за всеки клас гнездо фабрики, които наследяват от този основен родител.

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

Вече имате достъп до вложените фабрики както следва:

artist_profile = create(:artist_profile)
musician_profile = create(:musician_profile)

Надявам се, че това помага на някого.


2 за отговор № 5

Изглежда, че полиморфните асоциации във фабриките се държат по същия начин, както редовните асоциации на Rails.

Така че има и друг по-малко подробен начин, ако не се интересувате от атрибутите на модела от страна на асоциацията "anywhere_to" (потребител в този пример):

# Factories
FactoryGirl.define do
sequence(:email) { Faker::Internet.email }

factory :user do
# you can predefine some user attributes with sequence
email { generate :email }
end

factory :artist do
# define association according to documentation
user
end
end

# Using in specs
describe Artist do
it "created from factory" do
# its more naturally to starts from "main" Artist model
artist = FactoryGirl.create :artist
artist.user.should be_an(User)
end
end

Асоциации на FactoryGirl: https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#associations


1 за отговор № 6

Понастоящем използвам това приложение за справяне с полиморфни асоциации в FactoryGirl:

В /spec/factories/users.rb:

FactoryGirl.define do

factory :user do
# attributes for user
end

# define your Artist factory elsewhere
factory :artist_user, parent: :user do
profile { create(:artist) }
profile_type "Artist"
# optionally add attributes specific to Artists
end

# define your Musician factory elsewhere
factory :musician_user, parent: :user do
profile { create(:musician) }
profile_type "Musician"
# optionally add attributes specific to Musicians
end

end

След това създайте записи както обикновено: FactoryGirl.create(:artist_user)