Scope Ex not working Rails

I write Hi, but SO would not allow this, so I am writing a longer sentence :) Hello, by the way.

It seems that my scope is not working.

I wrote this area:

scope :ordered, ->(field, order) { except(:order).order("#{field} #{order}") }

but when checking SQL, it returns the following:

 irb >p.levels.ordered("name", "ASC").to_sql => "SELECT \"levels\".* FROM \"levels\" WHERE (\"levels\".pie_id = 6 AND (\"levels\".\"parent_id\" = 0)) ORDER BY position ASC, name ASC" 

NOTE: position ASC should not be

But it works when adding except my area ...

 irb > p.levels.except(:order).ordered("name", "ASC").to_sql => "SELECT \"levels\".* FROM \"levels\" WHERE (\"levels\".pie_id = 6 AND (\"levels\".\"parent_id\" = 0)) ORDER BY name ASC" ` 

Is available in the area? Or do you see anything that could help me?

Ruby 1.9.2p290

Rails 3.0.14

thanks

+4
source share
3 answers

You probably already realized that you can achieve your goal using reorder . So my theory is why reorder works, and except does not.

It is important that methods like order , where , except handled by ActiveRecord::Relation instances, while scope, for example. ordered from your example, delegated by an instance of ActiveRecord::Relation for your model class.

some_relation.order(:x) method simply returns a new copy of some_relation with :x added to its order_values list. Similarly, some_relation.except(:order) will return a copy of some_relation with empty order_values . As long as the chain of calls consists of such relationship methods, except works as we expected.

The scope method call, when the scope is implemented as a lambda return relation, ends with the union of the model relation returned by scoped with the relation returned by lambda:

 scopes[name] = lambda do |*args| options = scope_options.is_a?(Proc) ? scope_options.call(*args) : scope_options relation = if options.is_a?(Hash) scoped.apply_finder_options(options) elsif options scoped.merge(options) # <- here options is what returned by your :ordered lambda else scoped end extension ? relation.extending(extension) : relation end 

And this merge does not retain the effect of except if it was made only for one of the combined relationships. If we combine a and b , and b has no order, but a , then the result will still be in order. Now reorder works with him with a trick: he sets the special flag reorder_flag in relation, which controls how the merge carries order_values .

Here is my test sample. I use default_scope to enter order in Product#scoped . In your example, the order is probably entered in Level#scoped by association in Pie , which might look like has_many :levels, :order => 'position' Level#scoped has_many :levels, :order => 'position' .

 class Product < ActiveRecord::Base default_scope order('id DESC') scope :random_order, lambda { r = order('random()') puts "from lambda: " + r.order_values.inspect r } end # in console: >> Product.scoped.order_values => ["id DESC"] >> Product.random_order.order_values from lambda: ["id DESC", "random()"] => ["id DESC", "id DESC", "random()"] # now if I change the first line of lambda to # r = except(:order).order('random()') >> Product.random_order.order_values from lambda: ["random()"] => ["id DESC", "random()"] 

As you can see, due to the fact that Product.scoped has an id DESC order, it appears as a result, despite the fact that it has been cleared of the relation returned by the scope.

Here is a list of links to relevant sources:

+3
source

Added scope defined in model

 scope :ordered, ->(field, order) { except(:order).order("#{field} #{order}") } 

I tried different combinations and all the work

 a.inspection_serial_numbers.ordered('part_serial_number', 'DESC').except(:order).ordered('id', 'DESC').to_sql => "SELECT `inspection_serial_numbers`.* FROM `inspection_serial_numbers` WHERE `inspection_serial_numbers`.`inspection_master_id` = 1 ORDER BY id DESC" a.inspection_serial_numbers.ordered('part_serial_number', 'DESC').except(:order).ordered('id', 'DESC').except(:order).ordered('is_active', 'ASC').to_sql => "SELECT `inspection_serial_numbers`.* FROM `inspection_serial_numbers` WHERE `inspection_serial_numbers`.`inspection_master_id` = 1 ORDER BY is_active ASC" 

Even if u combine the “ordered” region with the “exception” in any combination several times, the last “ordered” region is used to order

 a.inspection_serial_numbers.ordered('part_serial_number', 'DESC').ordered('id', 'ASC').except(:order).ordered('id', 'DESC').to_sql => "SELECT `inspection_serial_numbers`.* FROM `inspection_serial_numbers` WHERE `inspection_serial_numbers`.`inspection_master_id` = 1 ORDER BY id DESC" 

Buf it u wants to delete all areas, use 'unscoped'

 a.inspection_serial_numbers.ordered('id', 'ASC').unscoped.ordered('part_serial_number', 'DESC').to_sql => "SELECT \"inspection_serial_numbers\".* FROM \"inspection_serial_numbers\" ORDER BY part_serial_number DESC" 

see http://apidock.com/rails/ActiveRecord/SpawnMethods/except and http://apidock.com/rails/ActiveRecord/Base/unscoped/class

+1
source

The order of the method may be incorrect.

write order("#{field} #{order}").except(:order)

see rail guides

0
source

All Articles