Skip to content

Commit a81706a

Browse files
committed
Add ransacker for product variants option values
Introduce a ransacker `variants_option_values` on Spree::Product. This ransacker enables dynamic filtering combined with ransack on product variants option values. For now, this attribute is geared towards usage in the admin interface. https://activerecord-hackery.github.io/ransack/going-further/ransackers/
1 parent 556d11c commit a81706a

File tree

2 files changed

+61
-1
lines changed

2 files changed

+61
-1
lines changed

core/app/models/spree/product.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,16 @@ def find_or_build_master
131131

132132
alias :options :product_option_types
133133

134+
ransacker :variants_option_values, formatter: proc { |v|
135+
joins(variants_including_master: :option_values)
136+
.where(spree_option_values: { id: v })
137+
.pluck(:id)
138+
} do |parent|
139+
parent.table[:id]
140+
end
141+
134142
self.allowed_ransackable_associations = %w[stores variants_including_master master variants]
135-
self.allowed_ransackable_attributes = %w[name slug]
143+
self.allowed_ransackable_attributes = %w[name slug variants_option_values]
136144
self.allowed_ransackable_scopes = %i[available with_discarded with_all_variant_sku_cont with_kept_variant_sku_cont]
137145

138146
# @return [Boolean] true if there are any variants

core/spec/models/spree/product_spec.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,58 @@ class Extension < Spree::Base
641641
end
642642
end
643643

644+
context "ransacker :variants_option_values" do
645+
it "filters products based on option values of their variants" do
646+
product_1 = create(:product)
647+
option_value_1 = create(:option_value)
648+
create(:variant, product: product_1, option_values: [option_value_1])
649+
650+
result = Spree::Product.ransack(variants_option_values_in: [option_value_1.id]).result
651+
expect(result).to contain_exactly(product_1)
652+
end
653+
654+
it "returns multiple products for the same option value" do
655+
product_1 = create(:product)
656+
product_2 = create(:product)
657+
option_value_1 = create(:option_value)
658+
create(:variant, product: product_1, option_values: [option_value_1])
659+
create(:variant, product: product_2, option_values: [option_value_1])
660+
661+
result = Spree::Product.ransack(variants_option_values_in: [option_value_1.id]).result
662+
expect(result).to contain_exactly(product_1, product_2)
663+
end
664+
665+
it "returns no products if there is no match" do
666+
non_existing_option_value_id = 99999
667+
result = Spree::Product.ransack(variants_option_values_in: [non_existing_option_value_id]).result
668+
expect(result).to be_empty
669+
end
670+
671+
it "returns products that match any of the provided option value IDs" do
672+
product_1 = create(:product)
673+
product_2 = create(:product)
674+
option_value_1 = create(:option_value)
675+
option_value_2 = create(:option_value)
676+
create(:variant, product: product_1, option_values: [option_value_1])
677+
create(:variant, product: product_2, option_values: [option_value_2])
678+
679+
result = Spree::Product.ransack(variants_option_values_in: [option_value_1.id, option_value_2.id]).result
680+
expect(result).to contain_exactly(product_1, product_2)
681+
end
682+
683+
it "doesn't return products that have other option values not in the query" do
684+
product_1 = create(:product)
685+
product_2 = create(:product)
686+
option_value_1 = create(:option_value)
687+
option_value_2 = create(:option_value)
688+
create(:variant, product: product_1, option_values: [option_value_1])
689+
create(:variant, product: product_2, option_values: [option_value_2])
690+
691+
result = Spree::Product.ransack(variants_option_values_in: [option_value_1.id]).result
692+
expect(result).not_to include(product_2)
693+
end
694+
end
695+
644696
describe "ransack scopes" do
645697
context "available scope" do
646698
subject { described_class.ransack(available: true).result }

0 commit comments

Comments
 (0)