web-dev-qa-db-fra.com

Avec Rails 4, Model.scoped est obsolète mais Model.all ne peut pas le remplacer

Démarrer Rails 4, Model.scoped Est désormais obsolète.

DEPRECATION WARNING: Model.scoped is deprecated. Please use Model.all instead.

Mais, il y a une différence entre Model.scoped Et Model.all, C'est-à-dire que scoped.scoped Renvoie une étendue, tandis que all.all Exécute la requête.

On Rails 3:

> Model.scoped.scoped.is_a?(ActiveRecord::Relation)
=> true

On 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

Il y a des cas d'utilisation dans les bibliothèques/préoccupations qui retournent scoped quand il y a une condition pour faire quelque chose ou rien, comme ceci:

module AmongConcern
  extend ActiveSupport::Concern

  module ClassMethods
    def among(ids)
      return scoped if ids.blank?

      where(id: ids)
    end
  end
end

Si vous changez ce scoped en all, vous rencontrerez des problèmes aléatoires selon l'endroit où le among a été utilisé dans la chaîne de portée. Par exemple, Model.where(some: value).among(ids) exécuterait la requête au lieu de renvoyer une étendue.

Ce que je veux, c'est une méthode idempotente sur ActiveRecord::Relation Qui renvoie simplement une portée.

Que dois-je faire ici?

77
kenn

Il semble que where(nil) soit un véritable remplacement de scoped, qui fonctionne à la fois sur Rails 3 et 4. :(

63
kenn

Sur Rails 4.1 (beta 1), les travaux suivants fonctionnent:

Model.all.all.is_a?(ActiveRecord::Relation)
=> true

Il semble donc que ce problème a été corrigé, et dans 4.1.0 Model.scoped a été complètement supprimé.

25
Olivier Lacan

Comme mentionné dans l'un des commentaires, all est censé renvoyer une portée selon la documentation .

La documentation est correcte - elle retourne un ActiveRecord :: Relation, mais vous devez utiliser un point-virgule si vous voulez le voir dans la console:

pry(main)> u = User.all;

pry(main)> u.class

=> ActiveRecord::Relation::ActiveRecord_Relation_User
9
Jason Rust

En plus d'utiliser where(nil), vous pouvez également appeler clone si vous savez que self est une relation et obtenez le comportement identique d'appeler scoped sans argument , sans l'avertissement de dépréciation.

MODIFIER

J'utilise maintenant ce code en remplacement de scoped car je n'aime pas utiliser where(nil) partout où j'ai besoin de me procurer l'étendue actuelle:

     # 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

Je ne vois pas pourquoi les auteurs AR ne pourraient pas avoir fait quelque chose de similaire car comme l'OP le souligne all et scoped font pas se comportent de la même manière.

4
Andrew Hacking