Skip to content

Commit 6477ee8

Browse files
authored
Merge pull request #6408 from SuperGoodSoft/remove-product-filters-require
Remove product filters require
2 parents 154c123 + 74f3eac commit 6477ee8

2 files changed

Lines changed: 76 additions & 77 deletions

File tree

core/app/models/spree/taxon.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# frozen_string_literal: true
22

3-
require 'spree/core/product_filters'
4-
53
module Spree
64
class Taxon < Spree::Base
75
extend FriendlyId

core/lib/spree/core/product_filters.rb

Lines changed: 76 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,61 @@
22

33
module Spree
44
module Core
5-
# THIS FILE SHOULD BE OVER-RIDDEN IN YOUR SITE EXTENSION!
6-
# the exact code probably won't be useful, though you're welcome to modify and reuse
7-
# the current contents are mainly for testing and documentation
8-
9-
# To override this file...
10-
# 1) Make a copy of it in your sites local /lib/spree folder
11-
# 2) Add it to the config load path, or require it in an initializer, e.g...
5+
# THIS FILE SHOULD BE OVER-RIDDEN IN YOUR APP!
126
#
13-
# # config/initializers/spree.rb
14-
# require 'spree/product_filters'
7+
# Use this code as a reference or a starting point for your own product
8+
# filters.
159
#
10+
# To override this file make a copy of it in lib/spree/core and modify it.
1611

17-
# set up some basic filters for use with products
12+
# Each filter has two parts:
13+
#
14+
# * a parametrized named scope which expects a list of labels
15+
# * an object which describes/defines the filter
1816
#
19-
# Each filter has two parts
20-
# * a parametrized named scope which expects a list of labels
21-
# * an object which describes/defines the filter
17+
# The filter description has the following components:
2218
#
23-
# The filter description has three components
24-
# * a name, for displaying on pages
25-
# * a named scope which will 'execute' the filter
26-
# * a mapping of presentation labels to the relevant condition (in the context of the named scope)
27-
# * an optional list of labels and values (for use with object selection - see taxons examples below)
19+
# * a name for displaying on pages
20+
# * a named scope which filters the products
21+
# * a mapping of presentation labels to the relevant condition (in the
22+
# context of the named scope)
23+
# * an optional list of labels and values (for use with object selection -
24+
# see taxons examples below)
2825
#
29-
# The named scopes here have a suffix '_any', following Ransack's convention for a
30-
# scope which returns results which match any of the inputs. This is purely a convention,
31-
# but might be a useful reminder.
26+
# The named scopes here have a suffix '_any', following Ransack's convention
27+
# for a scope which returns results which match any of the inputs. This is
28+
# purely a convention, but might be a useful reminder.
3229
#
33-
# When creating a form, the name of the checkbox group for a filter F should be
34-
# the name of F's scope with [] appended, eg "price_range_any[]", and for
35-
# each label you should have a checkbox with the label as its value. On submission,
36-
# Rails will send the action a hash containing (among other things) an array named
30+
# When creating a form, the name of the checkbox group for a filter F should
31+
# be the name of F's scope with [] appended, e.g. "price_range_any[]", and
32+
# for each label you should have a checkbox with the label as its value. On
33+
# submission, Rails will send the action a hash containing an array named
3734
# after the scope whose values are the active labels.
3835
#
39-
# Ransack will then convert this array to a call to the named scope with the array
40-
# contents, and the named scope will build a query with the disjunction of the conditions
41-
# relating to the labels, all relative to the scope's context.
36+
# Ransack will then convert this array to a call to the named scope with the
37+
# array contents, and the named scope will build a query with the
38+
# disjunction of the conditions relating to the labels, all relative to the
39+
# scope's context.
4240
#
43-
# The details of how/when filters are used is a detail for specific models (eg products
44-
# or taxons), eg see the taxon model/controller.
45-
46-
# See specific filters below for concrete examples.
41+
# The details of how/when filters are used is a detail for specific models.
42+
# For example, see the Taxon model/controller. See specific filters below
43+
# for concrete examples.
4744
module ProductFilters
48-
# Example: filtering by price
49-
# The named scope just maps incoming labels onto their conditions, and builds the conjunction
50-
# 'price' is in the base scope's context (ie, "select foo from products where ...") so
51-
# we can access the field right away
52-
# The filter identifies which scope to use, then sets the conditions for each price range
45+
# Example: Filtering by price
5346
#
54-
# If user checks off three different price ranges then the argument passed to
55-
# below scope would be something like ["$10 - $15", "$15 - $18", "$18 - $20"]
47+
# The named scope just maps incoming labels onto their conditions, and
48+
# builds the conjunction 'price' is in the base scope's context (e.g.
49+
# "select foo from products where ...") so we can access the field right
50+
# away. The filter identifies which scope to use, then sets the
51+
# conditions for each price range.
5652
#
53+
# If user checks off three different price ranges then the argument passed
54+
# to below scope would be something like ["$10 - $15", "$15 - $18", "$18 -
55+
# $20"].
5756
Spree::Product.add_search_scope :price_range_any do |*opts|
58-
conds = opts.map { |element| Spree::Core::ProductFilters.price_filter[:conds][element] }.reject(&:nil?)
59-
scope = conds.shift
60-
conds.each do |new_scope|
61-
scope = scope.or(new_scope)
62-
end
57+
scope = opts.filter_map { |element|
58+
Spree::Core::ProductFilters.price_filter[:conds][element]
59+
}.inject { |scope1, scope2| scope1.or(scope2) }
6360

6461
Spree::Product.joins(master: :prices).where(scope)
6562
end
@@ -83,24 +80,26 @@ def self.price_filter
8380
}
8481
end
8582

86-
# Example: filtering by possible brands
83+
# Example: Filtering by possible brands
8784
#
88-
# First, we define the scope. Two interesting points here: (a) we run our conditions
89-
# in the scope where the info for the 'brand' property has been loaded; and (b)
90-
# because we may want to filter by other properties too, we give this part of the
91-
# query a unique name (which must be used in the associated conditions too).
85+
# First, we define the scope. Two interesting points here:
9286
#
93-
# Secondly, the filter. Instead of a static list of values, we pull out all existing
94-
# brands from the db, and then build conditions which test for string equality on
95-
# the (uniquely named) field "p_brand.value". There's also a test for brand info
96-
# being blank: note that this relies on with_property doing a left outer join
97-
# rather than an inner join.
87+
# * we run our conditions in the scope where the info for the 'brand'
88+
# property has been loaded; and
89+
# * because we may want to filter by other properties too, we give this
90+
# part of the query a unique name (which must be used in the
91+
# associated conditions too).
92+
#
93+
# Second, instead of a static list of values, we pull out all existing
94+
# brands from the database. Then we build conditions which test for string
95+
# equality on the (uniquely named) field "p_brand.value". There's also a
96+
# test for brand info being blank. Note that this relies on
97+
# `with_property` doing a left outer join rather than an inner join.
9898
Spree::Product.add_search_scope :brand_any do |*opts|
99-
conds = opts.map { |value| ProductFilters.brand_filter[:conds][value] }.reject(&:nil?)
100-
scope = conds.shift
101-
conds.each do |new_scope|
102-
scope = scope.or(new_scope)
103-
end
99+
scope = opts.filter_map { |value|
100+
Spree::Core::ProductFilters.brand_filter[:conds][value]
101+
}.inject { |scope1, scope2| scope1.or(scope2) }
102+
104103
Spree::Product.with_property('brand').where(scope)
105104
end
106105

@@ -117,25 +116,27 @@ def self.brand_filter
117116
}
118117
end
119118

120-
# Example: a parameterized filter
121-
# The filter above may show brands which aren't applicable to the current taxon,
122-
# so this one only shows the brands that are relevant to a particular taxon and
123-
# its descendants.
119+
# Example: A parameterized filter
120+
#
121+
# The filter above may show brands which aren't applicable to the current
122+
# taxon, so this one only shows the brands that are relevant to a
123+
# particular taxon and its descendants.
124124
#
125-
# We don't have to give a new scope since the conditions here are a subset of the
126-
# more general filter, so decoding will still work - as long as the filters on a
127-
# page all have unique names (ie, you can't use the two brand filters together
128-
# if they use the same scope). To be safe, the code uses a copy of the scope.
125+
# We don't need to give a new scope since the conditions here are a subset
126+
# of the more general filter, so decoding will still work as long as the
127+
# filters on a page all have unique names (i.e. you can't use the two
128+
# brand filters together if they use the same scope). To be safe, the code
129+
# uses a copy of the scope.
129130
#
130-
# HOWEVER: what happens if we want a more precise scope? we can't pass
131-
# parametrized scope names to Ransack, only atomic names, so couldn't ask
132-
# for taxon T's customized filter to be used. BUT: we can arrange for the form
133-
# to pass back a hash instead of an array, where the key acts as the (taxon)
134-
# parameter and value is its label array, and then get a modified named scope
135-
# to get its conditions from a particular filter.
131+
# However, if we want a more precise scope, we can't pass parametrized
132+
# scope names to Ransack, only atomic names. We can't ask for taxon T's
133+
# customized filter to be used, but we can arrange for the form to pass
134+
# back a hash instead of an array where the key acts as the taxon
135+
# parameter and value is its label array, and then get a modified named
136+
# scope to get its conditions from a particular filter.
136137
#
137-
# The brand-finding code can be simplified if a few more named scopes were added to
138-
# the product properties model.
138+
# The brand-finding code could be simplified if a few more named scopes
139+
# were added to the product properties model.
139140
Spree::Product.add_search_scope :selective_brand_any do |*opts|
140141
Spree::Product.brand_any(*opts)
141142
end

0 commit comments

Comments
 (0)