Область использования, за исключением того, что не работает Rails

Я пишу привет, но ТАК не позволил, поэтому я пишу более длинное предложение :) Кстати, привет.

Похоже, мой прицел не работает.

Я написал эту область:

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

но он возвращает следующее при проверке SQL:

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"

ПРИМЕЧАНИЕ. position ASC там быть не должно.

Но это работает при добавлении, кроме как перед моей областью...

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" `

Доступно только в области видимости? Или вы видите что-нибудь, что могло бы мне помочь, пожалуйста?

Рубин 1.9.2p290

Рельсы 3.0.14

Спасибо


person Bachet    schedule 17.08.2012    source источник


Ответы (3)


Вы, наверное, уже поняли, что можете достичь своей цели, используя reorder. Вот моя теория, почему reorder работает, а except нет.

Важно, чтобы такие методы, как order, where, except, обрабатывались экземплярами ActiveRecord::Relation, в то время как области действия, например. ordered из вашего примера делегируются экземпляром ActiveRecord::Relation вашему классу модели.

Метод some_relation.order(:x) просто возвращает свежую копию some_relation с добавлением :x в список order_values. Аналогично, some_relation.except(:order) вернет копию some_relation с пустым order_values. Пока цепочка вызовов состоит из таких методов отношения, except работает так, как мы и ожидали.

Вызов метода области видимости, когда область действия реализована как отношение, возвращающее лямбда, заканчивается слиянием отношения модели, возвращаемого scoped, с отношением, возвращаемым лямбдой:

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

И это merge не сохраняет эффект except, если это было сделано только для одного из объединяемых отношений. Если мы объединим a и b, и b не будет иметь установленный порядок, а a задаст, результат все равно будет иметь порядок. Теперь reorder работает с хитростью: он устанавливает специальный флаг reorder_flag на отношение, которое контролирует, как merge переносит order_values.

Вот мой тестовый образец. Я использую default_scope, чтобы ввести порядок в Product#scoped. В вашем примере порядок, вероятно, вводится в Level#scoped путем ассоциации в Pie, которая может выглядеть как 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()"]

Как видите, из-за того, что Product.scoped имеет порядок id DESC, он появляется в результате, несмотря на то, что он был очищен от отношения, возвращаемого областью видимости.

Вот список ссылок на соответствующие источники:

person Serge Balyuk    schedule 04.09.2012
comment
Эй, вроде неплохо, скоро посмотрю. Спасибо за ответ - person Bachet; 18.09.2012

Добавлена ​​область, которую вы определили в модели

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

Пробовал разные комбинации и все работает

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" 

Даже если вы комбинируете «упорядоченную» область с «кроме» в любых комбинациях несколько раз, для упорядочения используется последняя «упорядоченная» область

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" 

Если вы хотите удалить все области, используйте '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" 

см. http://apidock.com/rails/ActiveRecord/SpawnMethods/except и http://apidock.com/rails/ActiveRecord/Base/unscoped/class

person prasad.surase    schedule 30.08.2012
comment
Эй, вроде тоже неплохо, скоро посмотрю. Спасибо за ответ - person Bachet; 18.09.2012

порядок методов может быть неправильным.

надо написать order("#{field} #{order}").except(:order)

см. руководство по рельсам

person utwang    schedule 19.08.2012
comment
Чего я хочу добиться, так это сбросить условие заказа по умолчанию, чтобы сразу после этого установить новый заказ. То, как вы показываете, удаляет порядок, который вы только что установили. Тогда в запросе не будет условия порядка. Посмотрите ссылку, которую вы дали. Спасибо в любом случае - person Bachet; 20.08.2012