2016-04-22 5 views
0

Ich versuche, eine gültige Fabrik mit verschachtelten Attrs erstellen, aber nicht herausfinden, wie es geht. Ich kann es nicht mit create nachher machen, da dank der Validierung bei der Produkterstellung auch die geschachtelten Attribute erstellt werden sollen.verschachtelte Attr mit Factory bei der Erstellung

Wie kann ich eine gültige Fabrik erstellen?

product.rb

has_many :industry_products, dependent: :destroy, inverse_of: :product 
has_many :industries, through: :industry_products 
has_many :product_features, dependent: :destroy 
has_many :product_competitions, dependent: :destroy 
has_many :product_usecases, dependent: :destroy 
accepts_nested_attributes_for :industry_products, reject_if: :all_blank, allow_destroy: true 
accepts_nested_attributes_for :product_features, reject_if: :all_blank, allow_destroy: true 
accepts_nested_attributes_for :product_competitions, reject_if: :all_blank, allow_destroy: true 
accepts_nested_attributes_for :product_usecases, reject_if: :all_blank, allow_destroy: true 
validate :product_industries_limit 
validate :product_features_limit 
validate :product_competitions_limit 
validate :product_usecases_limit 

# other 3 validation method (features, competitions, usecases) are the same 
def product_industries_limit 
    if self.industries.reject(&:marked_for_destruction?).count > 5 
    self.errors.add :base, "You can't choose more than 5 industries." 
    elsif self.industries.reject(&:marked_for_destruction?).blank? 
    self.errors.add :base, "You have to choose at least 1 industry." 
    end 
end 

Fabriken

factory :product, class: Product do 
    name { Faker::Commerce.product_name } 
    company { Faker::Company.name } 
    website { 'https://example.com' } 
    oneliner { Faker::Lorem.sentence } 
    description { Faker::Lorem.paragraph } 
    user 

    trait :product_with_nested_attrs do 
    after(:create) do |product| 
     create(:product_competititon, product: product) 
     create(:product_usecase, product: product) 
     create(:product_feature, product: product) 
    end 
    end 

    trait :with_children do 
    ignore do 
     product_competition { build :product_competition } 
     product_usecase { build :product_usecase } 
     product_feature { build :product_feature } 
    end 

    after(:build) do |product, evaluator| 
     if evaluator.product_competitions.present? 
     product.product_competitions = evaluator.product_competitions 
     else 
     product.product_competitions << evaluator.product_competition 
     end 

     if evaluator.product_usecases.present? 
     product.product_usecases = evaluator.product_usecases 
     else 
     product.product_usecases << evaluator.product_usecase 
     end 

     if evaluator.product_features.present? 
     product.product_features = evaluator.product_features 
     else 
     product.product_features << evaluator.product_feature 
     end 
    end 
    end 

    trait :with_product_all do 
    ignore do 
     product_competititon { build :product_competititon } 
     product_usecase { build :product_usecase } 
     product_feature { build :product_feature } 
    end 

    after(:build) do |product, evaluator| 
    # If you have to skip validation, add the following line. 
     product.class.skip_callback(:save, :after, :product_competitions_limit) 
     product.product_competitions = evaluator.product_competitions 

     product.class.skip_callback(:save, :after, :product_features_limit) 
     product.product_features = evaluator.product_features 

     product.class.skip_callback(:save, :after, :product_usecases_limit) 
     product.product_usecases = evaluator.product_usecases 
    end 
    end 

product_spec

let(:product) { FactoryGirl.create(:product) } 
let(:test_product) {create(:product, :product_with_nested_attrs) } 
let 
let(:product_with_attrs) { create(:product) do |product| 
          product.product_features.create(attributes_for(:product_feature)) 
          product.product_competitions.create(attributes_for(:product_competition)) 
          product.product_usecases.create(attributes_for(:product_usecase)) 
          end } 
let(:new_product) { create(:product, :with_children) } 
let(:new_product_2) { create(:product, :with_product_all) } 

#this throws NoMethodError: undefined method `with_indifferent_access' for #<String:0x007fa4ff6ad2d0> 
it "has a valid factory" do 
    attrs = attributes_for(:product).merge({ 
    user_id: user.id, 
    product_features_attributes: attributes_for(:product_feature), 
    product_usecases_attributes: attributes_for(:product_usecase), 
    product_competitions_attributes: attributes_for(:product_competition), 
    product_industry: attributes_for(:industry) 
    }) 
    expect(Product.new(attrs)).to be_valid 
end 

#this throws: ActiveRecord::RecordInvalid: Validation failed: 
#You have to choose at least 1 industry., You must have at least 1 product feature., You must name at least 1 competition., You must describe at least 1 usecase. 
it "has a valid factory 3" do 
    expect(test_product).to be_valid 
end 

#this throws the same: ActiveRecord::RecordInvalid: Validation failed: 
#You have to choose at least 1 industry., You must have at least 1 product feature., You must name at least 1 competition., You must describe at least 1 usecase. 
it "has a valid factory 4" do 
    expect(product_with_attrs).to be_valid 
end 

AKTUALISIERT:

#this throws: ActiveRecord::RecordInvalid: Validation failed: 
#You have to choose at least 1 industry., You must have at least 1 product feature., You must name at least 1 competition., You must describe at least 1 usecase. 
it "has a valid factory 5" do 
    expect(new_product).to be_valid 
end 


#this throws the same: ActiveRecord::RecordInvalid: Validation failed: 
#You have to choose at least 1 industry., You must have at least 1 product feature., You must name at least 1 competition., You must describe at least 1 usecase. 
it "has a valid factory 6" do 
    expect(new_product_2).to be_valid 
end 

#checking puts 
it "has a valid factory 7" do 
    p = build(:product, :with_children) 
    puts p.product_competitions #gives: #<ProductCompetition:0x007fa4fbdd6fb0> 
    expect(p).to be_valid 
end 

Antwort

1

Dieses Fabrikbeispiel hilft beim Erstellen von Produkt mit einem product_competition. Mit Merkmalen für jede Beziehung werden Fabriken kompostierbarer. Sie können die Validierung mit der skip_callback in der Fabrik überspringen (wenn Sie müssen).

trait :with_product_competititon do 
    ignore do 
    product_competititon { build :product_competititon } 
    end 

    after(:build) do |product, evaluator| 
    # If you have to skip validation, add the following line. 
    product.class.skip_callback(:save, :after, :product_competitions_limit) 
    product.product_competitions = [evaluator.product_competitions] 
    end 
end 

Wenn Sie nicht über Züge egal, das Objekt zu komponieren und wünschen eine Fabrik haben, alles zu tun, können Sie versuchen, diese

trait :with_children do 
    ignore do 
    product_competititon { build :product_competititon } 
    product_usecases { build :product_usecases } 
    product_features { build :product_features } 
    end 

    after(:build) do |product, evaluator| 
    if evaluator.product_competititons.present? 
     product.product_competititons = evaluator.product_competititons 
    else 
     product.product_competititons << evaluator.product_competititon 
    end 

    if evaluator.product_usecases.present? 
     product.product_usecases = evaluator.product_usecases 
    else 
     product.product_usecases << evaluator.product_usecase 
    end 

    if evaluator.product_features.present? 
     product.product_features = evaluator.product_features 
    else 
     product.product_features << evaluator.product_feature 
    end 
    end 

PS: Ich habe diesen Code nicht getestet haben.

+0

Shishir, ich habe 2 Fragen, hoffe du kannst mir helfen: Ich sehe die Vorteile von Merkmalen im Allgemeinen für 'has_many', etc. Ich bevorzuge es nicht, sie in der Fabrik zu erstellen (wieder im Allgemeinen). Ich kann einfach 'let (: profile) {create (: profile, user: user}' nennen, wo ich die Beziehung inline einrichte. Ist das ein guter Ansatz? 2 .: In diesem Fall muss das Produkt immer bei Ich denke, es ist anders. Sie kommen immer Hand in Hand. Also ich denke, 1 Fabrik passt hier besser. Stimmen Sie nicht zu? –

+0

Shishir, bitte überprüfen Sie auch meine vorherigen Kommentar. Warum nicht Sie Verwenden Sie "skip_callback" für das zweite Beispiel? –

+0

skip_callback war nur ein Beispiel, wenn Sie wollen, um skip_validation. Es ist nicht erforderlich. Um Ihre Frage von oben Kommentar zu beantworten, würde ich Produktfabrik verwenden, um Project_completion zu erstellen, wenn sie immer Hand in Hand kommen Ich mag Eigenschaften, weil sie Ihre Daten so zusammensetzen, dass sie lesbar für jemanden sind, der die Spezifikation liest. – Shishir

Verwandte Themen