activerecord - query - Con Rails 4, Model.scoped está en desuso, pero Model.all no puede reemplazarlo
rails find (4)
Starting Rails 4, Model.scoped
ahora está en desuso.
DEPRECATION WARNING: Model.scoped is deprecated. Please use Model.all instead.
Sin embargo, existe una diferencia en Model.scoped
y Model.all
, es decir, scoped.scoped
devuelve un ámbito, mientras que all.all
ejecuta la consulta.
En Rails 3:
> Model.scoped.scoped.is_a?(ActiveRecord::Relation)
=> true
En 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
Hay casos de uso en bibliotecas / inquietudes que devuelven un scoped
cuando hay un condicional para hacer algo o nada, como ese:
module AmongConcern
extend ActiveSupport::Concern
module ClassMethods
def among(ids)
return scoped if ids.blank?
where(id: ids)
end
end
end
Si cambiara este scoped
para all
, se enfrentarían a problemas aleatorios dependiendo de dónde se utilizó el among
en la cadena de alcance. Por ejemplo, Model.where(some: value).among(ids)
ejecutaría la consulta en lugar de devolver un ámbito.
Lo que quiero es un método idempotente en ActiveRecord::Relation
que simplemente devuelva un alcance.
¿Qué debería hacer aquí?
Además de usar where(nil)
, también puede llamar a clone
si sabe que self
es una relación y obtiene el mismo comportamiento de llamada con scoped
sin argumentos, sin la advertencia de desaprobación.
EDITAR
Ahora estoy usando este código como un reemplazo en el scoped
porque no me gusta usar where(nil)
todas partes necesito tener acceso al alcance actual:
# 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
No veo por qué los autores de AR no podrían haber hecho algo similar, ya que, como OP lo señala all
scoped
no se comporta de la misma manera.
Como se menciona en uno de los comentarios, se supone que all
debe devolver un alcance de acuerdo con los documentos .
Los documentos son correctos, devuelve una relación ActiveRecord ::, pero debe usar un punto y coma si desea verla en la consola:
pry(main)> u = User.all;
pry(main)> u.class
=> ActiveRecord::Relation::ActiveRecord_Relation_User
En Rails 4.1 (beta 1), funciona lo siguiente:
Model.all.all.is_a?(ActiveRecord::Relation)
=> true
Por lo tanto, parece que este problema se ha solucionado, y en 4.1.0 Model.scoped
se ha eliminado por completo.
Parece que where(nil)
es un reemplazo real del scoped
, que funciona tanto en Rails 3 como en 4. :(