Skip to content

Commit a42036d

Browse files
forkatajarednormanadammathyssofiabesenski4
committed
Reword product filter documentation
This change cleans up some of the formatting and language around how product filters should be constructed. Co-authored-by: Jared Norman <jared@super.gd> Co-authored-by: Adam Mueller <adam@super.gd> Co-authored-by: Sofia Besenski <sofia@super.gd>
1 parent e07a215 commit a42036d

1 file changed

Lines changed: 65 additions & 56 deletions

File tree

core/lib/spree/core/product_filters.rb

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,50 @@ module Core
99
#
1010
# To override this file make a copy of it in lib/spree/core and modify it.
1111

12-
# set up some basic filters for use with products
12+
# Each filter has two parts:
1313
#
14-
# Each filter has two parts
15-
# * a parametrized named scope which expects a list of labels
16-
# * an object which describes/defines the filter
14+
# * a parametrized named scope which expects a list of labels
15+
# * an object which describes/defines the filter
1716
#
18-
# The filter description has three components
19-
# * a name, for displaying on pages
20-
# * a named scope which will 'execute' the filter
21-
# * a mapping of presentation labels to the relevant condition (in the context of the named scope)
22-
# * an optional list of labels and values (for use with object selection - see taxons examples below)
17+
# The filter description has the following components:
2318
#
24-
# The named scopes here have a suffix '_any', following Ransack's convention for a
25-
# scope which returns results which match any of the inputs. This is purely a convention,
26-
# but might be a useful reminder.
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)
2725
#
28-
# When creating a form, the name of the checkbox group for a filter F should be
29-
# the name of F's scope with [] appended, eg "price_range_any[]", and for
30-
# each label you should have a checkbox with the label as its value. On submission,
31-
# Rails will send the action a hash containing (among other things) an array named
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.
29+
#
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
3234
# after the scope whose values are the active labels.
3335
#
34-
# Ransack will then convert this array to a call to the named scope with the array
35-
# contents, and the named scope will build a query with the disjunction of the conditions
36-
# 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.
3740
#
38-
# The details of how/when filters are used is a detail for specific models (eg products
39-
# or taxons), eg see the taxon model/controller.
40-
41-
# 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.
4244
module ProductFilters
43-
# Example: filtering by price
44-
# The named scope just maps incoming labels onto their conditions, and builds the conjunction
45-
# 'price' is in the base scope's context (ie, "select foo from products where ...") so
46-
# we can access the field right away
47-
# The filter identifies which scope to use, then sets the conditions for each price range
45+
# Example: Filtering by price
4846
#
49-
# If user checks off three different price ranges then the argument passed to
50-
# 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.
5152
#
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"].
5256
Spree::Product.add_search_scope :price_range_any do |*opts|
5357
conds = opts.map { |element| Spree::Core::ProductFilters.price_filter[:conds][element] }.reject(&:nil?)
5458
scope = conds.shift
@@ -78,18 +82,21 @@ def self.price_filter
7882
}
7983
end
8084

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

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

0 commit comments

Comments
 (0)