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?


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. :(


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.


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

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.


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.