Skip to content
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

Enhance product model with variants_option_values ransacker #5395

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion core/app/models/spree/product.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,26 @@ def find_or_build_master

alias :options :product_option_types

# The :variants_option_values ransacker filters Spree::Product based on
# variant option values ids.
#
# Usage:
# Spree::Product.ransack(
# variants_option_values_in: [option_value_id1, option_value_id2]
# ).result
ransacker :variants_option_values, formatter: proc { |v|
elia marked this conversation as resolved.
Show resolved Hide resolved
if OptionValue.exists?(v)
joins(variants_including_master: :option_values)
.where(spree_option_values: { id: v })
.distinct
.select(:id).arel
end
} do |parent|
parent.table[:id]
end

self.allowed_ransackable_associations = %w[stores variants_including_master master variants]
self.allowed_ransackable_attributes = %w[name slug]
self.allowed_ransackable_attributes = %w[name slug variants_option_values]
self.allowed_ransackable_scopes = %i[available with_discarded with_all_variant_sku_cont with_kept_variant_sku_cont]

# @return [Boolean] true if there are any variants
Expand Down
52 changes: 52 additions & 0 deletions core/spec/models/spree/product_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,58 @@ class Extension < Spree::Base
end
end

context "ransacker :variants_option_values" do
it "filters products based on option values of their variants" do
product_1 = create(:product)
option_value_1 = create(:option_value)
create(:variant, product: product_1, option_values: [option_value_1])

result = Spree::Product.ransack(variants_option_values_in: [option_value_1.id]).result
expect(result).to contain_exactly(product_1)
end

it "returns multiple products for the same option value" do
product_1 = create(:product)
product_2 = create(:product)
option_value_1 = create(:option_value)
create(:variant, product: product_1, option_values: [option_value_1])
create(:variant, product: product_2, option_values: [option_value_1])

result = Spree::Product.ransack(variants_option_values_in: [option_value_1.id]).result
expect(result).to contain_exactly(product_1, product_2)
end

it "returns no products if there is no match" do
non_existing_option_value_id = 99999
result = Spree::Product.ransack(variants_option_values_in: [non_existing_option_value_id]).result
expect(result).to be_empty
end

it "returns products that match any of the provided option value IDs" do
product_1 = create(:product)
product_2 = create(:product)
option_value_1 = create(:option_value)
option_value_2 = create(:option_value)
create(:variant, product: product_1, option_values: [option_value_1])
create(:variant, product: product_2, option_values: [option_value_2])

result = Spree::Product.ransack(variants_option_values_in: [option_value_1.id, option_value_2.id]).result
expect(result).to contain_exactly(product_1, product_2)
end

it "doesn't return products that have other option values not in the query" do
product_1 = create(:product)
product_2 = create(:product)
option_value_1 = create(:option_value)
option_value_2 = create(:option_value)
create(:variant, product: product_1, option_values: [option_value_1])
create(:variant, product: product_2, option_values: [option_value_2])

result = Spree::Product.ransack(variants_option_values_in: [option_value_1.id]).result
expect(result).not_to include(product_2)
end
end

describe "ransack scopes" do
context "available scope" do
subject { described_class.ransack(available: true).result }
Expand Down