Bei Rails 4 ist Model.scoped veraltet, Model.all kann es jedoch nicht ersetzen

76

Das Starten von Rails 4 Model.scopedist jetzt veraltet.

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

Aber gibt es einen Unterschied in Model.scopedund Model.all, das heißt, scoped.scopedgibt einen Rahmen, während all.allläuft die Abfrage.

Auf Schienen 3:

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

Auf Schienen 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

Es gibt Anwendungsfälle in Bibliotheken / Anliegen, die zurückkehren, scopedwenn eine Bedingung besteht, etwas oder nichts zu tun, wie zum Beispiel:

module AmongConcern
  extend ActiveSupport::Concern

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

      where(id: ids)
    end
  end
end

Wenn Sie dies ändern scoped, alltreten zufällige Probleme auf, je nachdem, wo das amongin der Bereichskette verwendet wurde. Zum Beispiel Model.where(some: value).among(ids)würde die Abfrage ausgeführt, anstatt einen Bereich zurückzugeben.

Was ich will, ist eine idempotente Methode ActiveRecord::Relation, die einfach einen Bereich zurückgibt.

Was soll ich hier machen?

kenn
quelle
Sind Sie sicher, dass " allführt die Abfrage aus" nicht nur ein Artefakt der Konsole ist? Die Quelle schlägt vor, dass es gut funktionieren sollte.
Mu ist zu kurz
Aber du bekommst diese Warnung nicht, also bekommst du die allvon scoping/named.rb, richtig? Und das allvon scoping/named.rbist, AFAIK, was Model.allverwendet.
Mu ist zu kurz

Antworten:

63

Es scheint, dass dies where(nil)ein echter Ersatz für scopedRails 3 und 4 ist. :(

kenn
quelle
56
Oh mein gott, wirklich? WTF.
David
1
Die Verfallswarnung sagt zu verwenden load.
Shanemcd
Es heißt, loadWENN Sie eifrig laden möchten, und in jedem Fall nimmt es einen Parameter (Bedingung), so scheint jetzt where(nil)(oder trueoder {}oder 1) der beste Ersatz fürscoped
ecoologic
Funktioniert nicht für meinen Fall: user.active_section.scoped.uniq(false)funktioniert user.active_section.all.uniq(false)oder user.active_section.where(nil).uniq(false)nicht.
Skully
Wie wäre es mit Schienen 5?
Chamnap
25

Auf Rails 4.1 (Beta 1) funktioniert Folgendes:

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

Es scheint also, dass dieses Problem behoben und in 4.1.0 Model.scopedvollständig entfernt wurde.

Olivier Lacan
quelle
2
Super, danke für das Update! Wenn Sie jedoch ein Edelsteinpfleger sind, müssen Sie die Verwendung fortsetzen, where(nil)bis 4.0.x nicht mehr unterstützt wird ...
kenn
Dies ist ein sehr alter Thread, aber wir aktualisieren erst jetzt und müssen auch die Unterstützung für Rails 3 und 4 beibehalten. Ist es vernünftig, etwas in der Art von zu tun if ActiveRecord::VERSION::MAJOR == 3 then Model.scoped else Model.all end?
Astorije
9

Wie in einem der Kommentare erwähnt, allsoll ein Bereich gemäß den Dokumenten zurückgegeben werden .

Die Dokumente sind korrekt - es wird zwar eine ActiveRecord :: Relation zurückgegeben, Sie müssen jedoch ein Semikolon verwenden, wenn Sie es in der Konsole anzeigen möchten:

pry(main)> u = User.all;

pry(main)> u.class

=> ActiveRecord::Relation::ActiveRecord_Relation_User
Jason Rust
quelle
Es ist irrelevant - versuchen User.all.all;Sie es und Sie erhalten die gleiche Warnung. Leider wird es nicht behoben, bis Rails 4.x oder sogar Rails 5. github.com/rails/rails/issues/12756
kenn
4

Zusätzlich zur Verwendung können where(nil)Sie auch anrufen, clonewenn Sie wissen, dass selfes sich um eine Beziehung handelt, und das identische Verhalten beim Aufrufen scopedohne Argumente erhalten, ohne die Warnung vor der Ablehnung.

BEARBEITEN

Ich verwende diesen Code jetzt als Ersatz für, scopedda ich ihn nicht gerne where(nil)überall verwende, um den aktuellen Bereich zu erreichen:

     # 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

Ich verstehe nicht, warum die AR-Autoren etwas Ähnliches nicht hätten tun können, da das OP darauf hinweist allund scopedsich nicht gleich verhält.

Andrew Hacking
quelle
Sie können keine cloneModellklasse aufrufen . (zB Model.clone) scopedarbeitete sowohl an Modellklassen als auch an Beziehungen.
Kenn
@ kenn Ja, deshalb habe ich oben gesagt, wenn du weißt, dass Selbst eine Beziehung ist.
Andrew Hacking