Ответ 1
Кажется, что where(nil)
является реальной заменой scoped
, которая работает как на Rails 3, так и на 4.: (
Запуск Rails 4, Model.scoped
теперь устарел.
DEPRECATION WARNING: Model.scoped is deprecated. Please use Model.all instead.
Но существует разница в Model.scoped
и Model.all
, то есть scoped.scoped
возвращает область, а all.all
запускает запрос.
В Rails 3:
> Model.scoped.scoped.is_a?(ActiveRecord::Relation)
=> true
В Rails 4:
> Model.all.all.is_a?(ActiveRecord::Relation)
DEPRECATION WARNING: Relation#all is deprecated. If you want to eager-load a relation, you can call #load (e.g. `Post.where(published: true).load`). If you want to get an array of records from a relation, you can call #to_a (e.g. `Post.where(published: true).to_a`).
=> false
В библиотеках/проблемах есть примеры использования, которые возвращают scoped
, когда есть условие сделать что-то или ничего, например:
module AmongConcern
extend ActiveSupport::Concern
module ClassMethods
def among(ids)
return scoped if ids.blank?
where(id: ids)
end
end
end
Если вы измените этот scoped
на all
, вы столкнетесь с случайными проблемами, зависящими от того, где among
использовался в цепочке областей видимости. Например, Model.where(some: value).among(ids)
будет запускать запрос вместо возврата области.
Я хочу использовать метод idempotent на ActiveRecord::Relation
, который просто возвращает область.
Что мне здесь делать?
Кажется, что where(nil)
является реальной заменой scoped
, которая работает как на Rails 3, так и на 4.: (
В Rails 4.1 (beta 1) работает следующее:
Model.all.all.is_a?(ActiveRecord::Relation)
=> true
Итак, похоже, эта проблема исправлена, а в 4.1.0 Model.scoped
полностью удалена.
Как упоминалось в одном из комментариев, all
должен возвращать область в соответствии с документами.
Документы верны - он возвращает ActiveRecord:: Relation, но вам нужно использовать полуточку, если вы хотите увидеть ее в консоли:
pry(main)> u = User.all;
pry(main)> u.class
=> ActiveRecord::Relation::ActiveRecord_Relation_User
В дополнение к использованию where(nil)
вы также можете вызвать clone
, если вы знаете, что self
является отношением и получает идентичное поведение вызова scoped
без аргументов, без предупреждения об устаревании.
ИЗМЕНИТЬ
Теперь я использую этот код в качестве замены для замены scoped
, так как мне не нравится использовать where(nil)
всюду, чтобы получить текущую область видимости:
# config/initializers/scoped.rb
class ActiveRecord::Base
# do things the modern way and silence Rails 4 deprecation warnings
def self.scoped(options=nil)
options ? where(nil).apply_finder_options(options, true) : where(nil)
end
end
Я не понимаю, почему авторы AR не могли сделать что-то подобное, так как OP указывает all
и scoped
do not вести себя одинаково.