2015-12-01 3 views
6

Ich habe eine ziemlich klobige Factory Girl-Eigenschaft, die Params akzeptiert und erstellt eine has_many Beziehung. Ich kann dieses Merkmal als Teil eines anderen Merkmals bezeichnen, um Merkmale zu trocknen oder es leichter zu machen, Merkmale zusammenzufassen, wenn man sie in Fabriken bringt. Was ich nicht weiß, ist, wie man Params an ein Merkmal weitergibt, wenn ich es von einem anderen Merkmal ausrufe oder was ich stattdessen tun soll.Call-Eigenschaft von einem anderen Merkmal mit Params in Factory_Girl

z.B.

FactoryGirl.define do 
    factory :currency do 
    name Forgery::Currency.description 
    sequence(:short_name) { |sn| "#{Forgery::Currency.code}#{sn}" } 
    symbol '$' 
    end 

    factory :price do 
    full_price { 6000 } 
    discount_price { 3000 } 
    currency 
    subscription 
    end 

    sequence(:base_name) { |sn| "subscription_#{sn}" } 

    factory :product do 
    name { generate(:base_name) } 
    type { "reading" } 
    duration { 14 } 


    trait :reading do 
     type { "reading subscription" } 
    end 

    trait :maths do 
     type { "maths subscription" } 
    end 

    trait :six_month do 
     name { "six_month_" + generate(:base_name) } 
     duration { 183 } 
    end 

    trait :twelve_month do 
     name { "twelve_month_" + generate(:base_name) } 
     duration { 365 } 
    end 

    factory :six_month_reading, traits: [:six_month, :reading] 
    factory :twelve_month_reading, traits: [:twelve_month, :reading] 

    trait :with_price do 
     transient do 
     full_price 6000 
     discount_price 3000 
     short_name 'AUD' 
     end 

     after(:create) do |product, evaluator| 
     currency = Currency.find_by(short_name: evaluator.short_name) || 
        create(:currency, short_name: evaluator.short_name) 
     create_list(
      :price, 
      1, 
      product: product, 
      currency: currency, 
      full_price: evaluator.full_price, 
      discount_price: evaluator.discount_price 
     ) 
     end 
    end 

    trait :with_aud_price do 
     with_price 
    end 

    trait :with_usd_price do 
     with_price short_name: 'USD' 
    end 
    end 
end 

create(:product, :with_aud_price) # works 
create(:product, :with_usd_price) # fails "NoMethodError: undefined method `with_price=' for #<Subscription:0x007f9b4f3abf50>" 

# What I really want to do 
factory :postage, parent: :product do 
    with_aud_price full_price: 795 
    with_usd_price full_price 700 
end 

Antwort

6

Der :with_price Merkmal muss in einer separaten Zeile von den anderen Attributen Sie einstellen, dh statt dessen sein:

diese
trait :with_usd_price do 
    with_price short_name: 'USD' 
end 

Verwendung:

trait :with_usd_price do 
    with_price 
    short_name: 'USD' 
end 
+0

Ich verstehe nicht wirklich, warum das funktioniert, aber ich bin sehr froh, dass es so ist. – jim

+0

Bei einer Vermutung scheint es unter der Haube Aufruf Merkmal A innerhalb Merkmal B macht Merkmal B eine Unterklasse von Merkmal A. Das würde bedeuten, dass es mehrere Vererbung unterstützt und wer weiß, was passiert, wenn beide Ihre Eigenschaften definieren die gleichen vorübergehenden Eigenschaften usw. etc denke, dass der erste oder der letzte Aufruf Vorrang hat. Es scheint ein wenig überraschend zu sein, die Vererbung wie einen Methodenaufruf zu definieren und nicht mit etwas wie der für Factory verwendeten "parent:: foo" -Syntax. – jim

+0

Ok. Ich habe mir das genauer angeschaut, es ist so gut wie es geht, aber ich kann das Beispiel am unteren Ende des Codebeispiels im OP immer noch nicht machen. Wenn ich in dieser Form versuche, bekomme ich 'FactoryGirl :: AttributeDefinitionError: Attribut bereits definiert: full_price'. Hmm ... Ich könnte es vielleicht mit Arrays für die transienten Eigenschaften arbeiten lassen. – jim

0

I‘ m auf factory_bot 4.8.2 und das Folgende ist, was für mich funktioniert:

trait :with_usd_price do 
    with_price 
    short_name 'USD' 
end