Spree core now uses Searchlogic version 2.1.13 (unless a new version appears whilst I am writing). This has meant a few changes to how search and pagination are set up, but also allowed a few details of Spree to be improved at the same time. Extension developers will benefit too – the new gem is much more flexible, and easy to use. Marcin (Swistak) suggested that it might even go a fair way to providing the functionality we wanted in product groups, and I think he has a good point.
So, what’s new? Searchlogic has been completely rewritten in version 2, and uses a different approach to version 1. It now focuses more on key functionality and less on reinventing the wheel, e.g. control of pagination has passed back to the pagination gems. As a result, the code has gone from ~2300 loc to ~420 loc. However, several useful bits of functionality have been added. For more information, see the github project and the rdoc documentation.
I think there’s two sides to this new version. Firstly, it provides a wide set of named scopes which you can use alongside existing ones. These are all dynamically generated, and able to follow model structure – including all associations, and to apply a range of tests to the fields identified. Here’s some examples from the documentation:
- Within a model, filtering by various tests on fields:
User.username_equals(“bjohnson”)<br /> User.username_begins_with(“bjohnson”)<br /> User.username_like(“bjohnson”)
- Using associations (note the change of naming convention):
- Scopes for ordering:
- List modifiers, eg test on a list of values for any or all hits – this is very useful (and more efficient than doing it yourself)
Secondly, there’s the search aspect. This allows searches to be defined on top of some base scope, and customized in various ways. The search option names follow the same pattern as the named scopes above, and can be chained together or set separately. For example:
search = User.search(:username_equals => “bjohnson”, :age_less_than => 30)<br /> search.email_contains(“bjohnson”)<br /> search.age_gt = 20</p>
Gotcha #1: it isn’t possible in this version to over-ride the a search in the base scope by supplying options to the search, eg. check out the following example. It could be a bug.
scope = Product.ascend_by_master_price<br /> search = scope.search().order(“descend_by_master_price”)<br /> search.scope(:find)</p>
As for a chain of named scopes, you can get results out of a search with
first, etc – or use some pagination library like
will_paginate to handle limited fetches. See
app/controllers/admin/product_controller.rb for an example of this in use.
Form handling is also much easier. There’s no need to include
'admin' in the submit path (it is detected automatically), and no need for
fields_for to access associated records – you just need to adjust the field names to follow the new naming convention, eg for product search, you can search for
variants_sku_contains to look for a substring in the
sku field of any of the product’s variants. Particularly note how the check boxes have been brought within the searchlogic framework: the concepts represented by the check boxes map directly to one of the new-format searchlogic queries, so naming the box after the relevant condition is all you need to do.
Finally, if you are migrating from an earlier version, you need to run
rake spree:upgrade and check that the will_paginate gem is listed in
config/environment.rb, and also ensure that
config/initializers/searchlogic.rb has been removed.