Skip to content

Instantly share code, notes, and snippets.

@Whelton
Created October 8, 2015 16:40
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save Whelton/42cf3536903a95c04ac8 to your computer and use it in GitHub Desktop.
Save Whelton/42cf3536903a95c04ac8 to your computer and use it in GitHub Desktop.
Add sorting to your taxon page in Spree (based off: http://berk.es/2015/05/09/add-sorting-to-your-product-page-in-spree/)

Add sorting to your product taxon page in Spree

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.

TL;DR

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.

Explanation

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.

Fin

Happy days. Checkout the attached taxons_controller_decorator.rb the working code for sorting taxons.

Thank you @berkes for the original guide.

# app/controllers/spree/taxons_controller_decorator.rb
# Sorting based off: http://berk.es/2015/05/09/add-sorting-to-your-product-page-in-spree/
# Taxon specific code from: https://gist.github.com/Whelton/42cf3536903a95c04ac8
module Spree
TaxonsController.class_eval do
helper_method :sorting_param
alias_method :old_show, :show
def show
old_show # Like calling super: http://stackoverflow.com/a/13806783/73673
# Remove default `:in_taxon` `ORDER_BY` & apply sorting scope if `sorting` param is present
@products = @products.reorder('').send(sorting_scope) if params[:sorting].present?
end
def sorting_param
params[:sorting].try(:to_sym) || default_sorting
end
private
def sorting_scope
allowed_sortings.include?(sorting_param) ? sorting_param : default_sorting
end
def default_sorting
:ascend_by_updated_at
end
def allowed_sortings
[:descend_by_master_price, :ascend_by_master_price, :ascend_by_updated_at]
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment