Standard-Sortierreihenfolge für ein Schienenmodell?

255

Ich möchte in meinem Modell eine Standardsortierreihenfolge angeben.

Wenn ich also a .where()ohne Angabe eines mache .order(), wird die Standardsortierung verwendet. Wenn ich jedoch eine .order()anmelde, wird die Standardeinstellung überschrieben.

Justin Tanner
quelle

Antworten:

544

default_scope

Dies funktioniert für Rails 4+:

class Book < ActiveRecord::Base
  default_scope { order(created_at: :desc) }
end

Für Rails 2.3, 3 benötigen Sie stattdessen Folgendes:

default_scope order('created_at DESC')

Für Schienen 2.x:

default_scope :order => 'created_at DESC'

Wo created_atist das Feld, in dem die Standardsortierung durchgeführt werden soll?

Hinweis: ASC ist der Code für aufsteigende zu verwenden und DESC ist für den Abstieg ( desc, NICHT dsc !).

scope

Sobald Sie daran gewöhnt sind, können Sie auch Folgendes verwenden scope:

class Book < ActiveRecord::Base
  scope :confirmed, :conditions => { :confirmed => true }
  scope :published, :conditions => { :published => true }
end

Für Rails 2 benötigen Sie named_scope.

:publishedUmfang gibt Ihnen Book.publishedstatt Book.find(:published => true).

Seit Rails 3 können Sie diese Methoden miteinander verketten, indem Sie sie mit Punkten zwischen ihnen verketten. Mit den oben genannten Bereichen können Sie sie jetzt verwenden Book.published.confirmed.

Bei dieser Methode wird die Abfrage erst ausgeführt, wenn die tatsächlichen Ergebnisse benötigt werden (verzögerte Auswertung). Daher können 7 Bereiche miteinander verkettet werden, was jedoch nur zu einer tatsächlichen Datenbankabfrage führt, um Leistungsprobleme bei der Ausführung von 7 separaten Abfragen zu vermeiden.

Sie können einen übergebenen Parameter wie ein Datum oder eine Benutzer-ID verwenden (etwas, das sich zur Laufzeit ändert und daher diese 'verzögerte Auswertung' mit einem Lambda wie diesem benötigt:

scope :recent_books, lambda 
  { |since_when| where("created_at >= ?", since_when) }
  # Note the `where` is making use of AREL syntax added in Rails 3.

Schließlich können Sie den Standardbereich deaktivieren mit:

Book.with_exclusive_scope { find(:all) } 

oder noch besser:

Book.unscoped.all

Dadurch werden alle Filter (Bedingungen) oder Sortierungen (Reihenfolge nach) deaktiviert.

Beachten Sie, dass die erste Version in Rails2 + funktioniert, während die zweite (ohne Gültigkeitsbereich) nur für Rails3 + gilt


Also ... wenn du denkst, hmm, das sind also genau wie Methoden, dann ... yup, genau das sind diese Bereiche!
Sie sind wie haben, def self.method_name ...code... endaber wie immer mit Rubin sind sie nette kleine syntaktische Abkürzungen (oder 'Zucker'), um die Dinge für Sie einfacher zu machen!

Tatsächlich handelt es sich um Methoden auf Klassenebene, da sie mit einem Satz von "allen" Datensätzen arbeiten.

Ihr Format ändert sich jedoch. Bei Schienen 4 wird bei Verwendung von #scope ohne Übergabe eines aufrufbaren Objekts eine Warnung vor Verfall angezeigt. Zum Beispiel Bereich: rot, wobei (Farbe: 'rot') in geändert werden soll scope :red, -> { where(color: 'red') }.

Als Randnotiz kann bei falscher Verwendung das Standard- _scope missbraucht / missbraucht werden.
Hier geht es hauptsächlich darum, wann es für Aktionen wie wheredas Einschränken (Filtern) der Standardauswahl (eine schlechte Idee für einen Standard) verwendet wird, anstatt nur zum Ordnen von Ergebnissen verwendet zu werden. Verwenden Sie
für die whereAuswahl einfach die regulären benannten Bereiche. und fügen Sie diesen Bereich in die Abfrage ein, z. B. Book.all.publishedwo publishedsich ein benannter Bereich befindet.

Zusammenfassend lässt sich sagen, dass die Bereiche wirklich großartig sind und Ihnen dabei helfen, die Dinge für einen DRYer-Ansatz mit „Fat Model Thin Controller“ in das Modell zu integrieren.

Michael Durrant
quelle
1
Bitte beachten Sie die Warnung von Dave Thomas bezüglich der Verwendung von default_scope, bevor Sie es wie in diesem Beitrag beschrieben verwenden: pragdave.blogs.pragprog.com/pragdave/2012/03/…
reto
3
Wäre es nicht sicherer default_scope { order("#{table_name}.created_at DESC") }?
Cyrilchampier
37
Schienen 4:default_scope { order(created_at: :desc) }
Marcus
2
Wenigstens 4.2.6scheint durch sortieren updated_atnicht created_at.
Ain Tohvri
2
@AinTohvri ist richtig. Das hat mich in Rails 4.2 überrascht. Warum updated_atstandardmäßig sortieren ? : - |
Sixty4bit
112

Ein kurzes Update zu Michaels hervorragender Antwort oben.

Für Rails 4.0+ müssen Sie Ihre Sortierung in einen Block wie folgt einfügen:

class Book < ActiveRecord::Base
  default_scope { order('created_at DESC') }
end

Beachten Sie, dass die order-Anweisung in einem Block steht, der durch geschweifte Klammern gekennzeichnet ist.

Sie haben es geändert, weil es zu einfach war, etwas Dynamisches (wie die aktuelle Zeit) einzugeben. Dadurch wird das Problem behoben, da der Block zur Laufzeit ausgewertet wird. Wenn Sie keinen Block verwenden, wird folgende Fehlermeldung angezeigt:

Die Unterstützung für den Aufruf von #default_scope ohne Block wurde entfernt. Zum Beispiel anstelle von default_scope where(color: 'red')bitte verwendendefault_scope { where(color: 'red') } . (Alternativ können Sie auch self.default_scope neu definieren.)

Wie @Dan in seinem Kommentar unten erwähnt, können Sie eine rubinrotere Syntax wie folgt verwenden:

class Book < ActiveRecord::Base
  default_scope { order(created_at: :desc) }
end

oder mit mehreren Spalten:

class Book < ActiveRecord::Base
  default_scope { order({begin_date: :desc}, :name) }
end

Danke @Dan !

Paul Oliver
quelle
28
In Rails 4 kann dies auch so geschrieben werden, als default_scope { order(created_at: :desc) }ob Sie wie ich versuchen, die SQL-Syntax in Rails zu minimieren. <br/> Wenn Sie mehrere Spalten zum Ordnen haben und die neue Syntax verwenden möchten, müssen Sie möglicherweise den desc umbrechen Spalten in Schnurrbärten wie diesedefault_scope { order({begin_date: :desc}, :name) }
Dan
1
@Dan - Ihr Kommentar eliminiert nicht nur SQL, sondern ist auch eine eher rubinrote Syntax.
B Seven