Sology / smart_listing

Ruby on Rails data listing gem with built-in sorting, filtering and in-place editing.
http://showcase.sology.eu/smart_listing
MIT License
478 stars 138 forks source link

Improve compatibility with Mongoid #150

Closed ghost closed 4 months ago

ghost commented 6 years ago

We've been using smart_listing with Mongoid successfully, but after upgrading some packages, the sorting function stopped working. I don't know why exactly it stopped working, but I think I found out why it isn't working right now :)

The problem is this line:

@collection = @collection.order(sort_keys.collect{|s| "#{s[1]} #{@sort[s[0]]}" if @sort[s[0]]}.compact) if @sort && !@sort.empty?

When key "bla" is set to descending, I noticed that a query with "bla desc" => -1 is executed, which doesn't sort anything since there's no key "bla desc". I've tracked this down to Mongoid doing some magic with arrays: https://github.com/mongodb/mongoid/blob/master/lib/mongoid/criteria/queryable/extensions/array.rb#L110 That code, when called like this: ["bla desc"].__sort_option__ will output {"bla desc"=>-1}. On the other hand, if "bla desc".__sort_option__ is called (https://github.com/mongodb/mongoid/blob/master/lib/mongoid/criteria/queryable/extensions/string.rb#L56), the result is {:bla=>-1}.

The order_by() method (https://github.com/mongodb/mongoid/blob/master/lib/mongoid/criteria/queryable/optional.rb#L189) calls criterion.__sort_option__ for every parameter criterion, so order_by(["bla desc"]) tries to order with {"bla desc"=>-1}, while order_by("bla desc") (which doesn't work) tries to order with {:bla=>-1} (which orders by bla as expected).

This PR adds a * to @collections.order(sort_keys.collect{...}) to make sure that the array generated by sort_keys.collect{...} is not passed as an array parameter, but that the array's elements are passed as parameters.

I don't think this should have any negative impact on other backends, but should improve compatibility in general (after all, the documentation doesn't mention arrays as parameters).