-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Spree::Variant inconsistency due to lack of product association #3043
Fix Spree::Variant inconsistency due to lack of product association #3043
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job @rubenochiavone ! 👏
core/app/models/spree/variant.rb
Outdated
raise 'No master variant found to infer price' unless product && product.master | ||
self.price = product.master.price | ||
end | ||
self.price = product.master.price if price.nil? && Spree::Config[:require_master_price] && !is_master? && product && product.master |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about a guard clause being this long, but it's certainly not blocking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, it got quite long. Ruby's statement if condition
is too good to don't use it. 😄
@kennyadsl contribution might reduce it though - #3043 (comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I agree with his feedback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, left a couple of questions 🙂
core/app/models/spree/variant.rb
Outdated
@@ -73,7 +73,7 @@ class Variant < Spree::Base | |||
|
|||
before_validation :set_cost_currency | |||
before_validation :set_price |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about moving if: -> { product && product.master }
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -73,7 +73,7 @@ class Variant < Spree::Base | |||
|
|||
before_validation :set_cost_currency | |||
before_validation :set_price | |||
before_validation :build_vat_prices, if: -> { rebuild_vat_prices? || new_record? } | |||
before_validation :build_vat_prices, if: -> { rebuild_vat_prices? || new_record? && product } | |||
|
|||
validate :check_price |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about adding a presence
validation on the product
here? There are too many places where Solidus gives for granted that a product should be associated with a variant and I think it could make sense to don't allow saving a variant without a product associated. Also, this way users will have the right validation message attached to the invalid object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, after reviewing the code I'm having second thoughts. How can we validate product presence in variant if product requires a master variant to be present?
The funny thing is that product automatically builds master variant, but I was unable to find build_master
method definition. Maybe I'm missing something
solidus/core/app/models/spree/product.rb
Lines 74 to 76 in adc7534
def find_or_build_master | |
master || build_master | |
end |
Any idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
build_master
is a method coming from has_one association. That variant will be associated with the product automatically so I think it will be valid, even with the proposed product presence validation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
f9a67b7
to
f51633b
Compare
@@ -3,6 +3,13 @@ | |||
require 'rails_helper' | |||
|
|||
RSpec.describe Spree::Variant, type: :model do | |||
context "new instance" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rubenochiavone I think this example readability may benefit from using Rspec implicit subject. In Rspec the default subject
is an instance of the class being specified (similar to described_class.new(args)
but without any arguments... see here):
it { expect(subject).to be_invalid }
or, even more concisely:
it { is_expected.to be_invalid }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoa, that's great and works perfectly! Do you mind if I add a reference to implicit subject?
it { is_expected.to be_invalid } # implicitly defined subject, see https://relishapp.com/rspec/rspec-core/v/3-5/docs/subject/implicitly-defined-subject
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm 👍 on using this syntax but 👎 on adding a code comment. I think you could add a reference in the commit description instead (please keep it all in a single commit 🙂).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, cool. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Remove raising an error if price can't be inferred using product.master.price. Reporting missing product is enough for an invalid variant instance - add product presence validation. Also add product verification before generating VAT prices for variant. Specs improvements includes usage of implicitly defined subject, see https://relishapp.com/rspec/rspec-core/v/3-5/docs/subject/implicitly-defined-subject.
f51633b
to
7b80a71
Compare
@rubenochiavone thanks! 🎉 |
Description
Spree::Variant
new instance throw error during validation because it lacks a product association. The lack of product causesproduct.master.price
Module::DelegationError
to be raised because to generate VAT prices,variant.tax_category
is required and this method is delegated toproduct.tax_category
To fix it, removed raising an error if price can't be inferred using
product.master.price
. Reporting missing product is enough for an invalid variant instance. Also add product verification before generating VAT prices for variant.Closes #3036
Checklist: