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
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? –
Shishir, bitte überprüfen Sie auch meine vorherigen Kommentar. Warum nicht Sie Verwenden Sie "skip_callback" für das zweite Beispiel? –
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