So in following @berkes 'Add sorting to your product page in Spree' guide, I tried to repeat with my taxons controller. However there was no difference in order, despite the scopes being applied.
Another commenter Adam shared my frustration: 'How would I make this work for taxons as well? Everything I try doesn't work'.
After a little bit of research, I figured it out.
Spree::TaxonsController
applies an .order()
when scoping for the products in the taxon (to maintain their assigned position, you know when you drag them around in the list in admin: /admin/taxons
).
This invalidates any subsequent order
(like when we try order/sort by price, etc). Trick is to remove any ORDER_BY
with .reorder('')
before we apply any future scopes (like :ascend_by_master_price
).
See the attached taxons_controller_decorator.rb
for the working code.
The code in guide worked for the products_controller
as that didn't call any scope that applied an ORDER_BY
that would invalidate the sort by scopes, relevant code here.
The products_controller#index
combined with our products_controller_decorator#index
ultimately runs something like:
@searcher = build_searcher(params.merge(include_images: true))
@products = @searcher.retrieve_products
...
# Below same as: @products.joins(:master => :default_price).order("#{price_table_name}.amount ASC")
@products.send(:ascend_by_master_price)
Which ends the sql statement in ...ORDER BY "spree_prices".amount ASC LIMIT 12 OFFSET 0
.
Great that works and we get our products acending by master price.
However the taxons_controller
includes a taxon (who would guess), relevant code here, applies the in_taxon
scope, which applies an .order()
, relevant code here. This .order()
is to order by the position assigned to the product in the taxon (you know the drag interface in the admin: /admin/taxons
).
The taxons_controller#show
combined with our taxons_controller_decorator#show
ultimately runs something like:
@searcher = build_searcher(params.merge(taxon: @taxon.id, include_images: true)) # Includes `:in_taxon` scope
@products = @searcher.retrieve_products
...
# Below same as: @products.joins(:master => :default_price).order("#{price_table_name}.amount ASC")
@products.send(:ascend_by_master_price)
Which ends the sql statement in ...ORDER BY spree_products_taxons.position ASC, "spree_prices".amount ASC
. Priority is given to ordering by the position, which makes the amount ordering invalid/useless.
So the solution is to remove the previous ORDER BY spree_products_taxons.position ASC
by applying .reorder('')
, before applying the :ascend_by_master_price
scope (but we want to maintain position if no sorting
param is given).
Like so in taxons_controller_decorator#show
:
...
# Remove default `:in_taxon` `ORDER_BY` & apply sorting scope if `sorting` param is present
@products = @products.reorder('').send(sorting_scope) if params[:sorting].present?
Which ends the sql statement in ...ORDER BY "spree_prices".amount ASC LIMIT 12 OFFSET 0
and gives us back our products in the taxon ascending by master price.
Happy days. Checkout the attached taxons_controller_decorator.rb
the working code for sorting taxons.
Thank you @berkes for the original guide.