Schienen Umfang gibt alle statt nil
Ich in ein seltsames Problem erstellen eines Bereichs und mit der first
finder. Es scheint, als ob mit first
als Teil der Abfrage in einem Bereich machen es alle Ergebnisse zurückgegeben, wenn keine Ergebnisse gefunden werden. Wenn Ergebnisse gefunden werden, wird es richtig das erste Ergebnis.
Ich habe setup ein sehr einfacher test, um dies zu demonstrieren:
class Activity::MediaGroup < ActiveRecord::Base
scope :test_fail, -> { where('1 = 0').first }
scope :test_pass, -> { where('1 = 1').first }
end
Hinweis: für diesen test habe ich festgelegt, wo die Bedingungen zu entsprechen, zeichnet oder nicht. In Wirklichkeit bin ich die Abfrage basiert auf den realen Bedingungen, und immer die gleiche seltsame Verhalten.
Hier sind die Ergebnisse von dem fehlerhaften Rahmen. Wie Sie sehen können, macht es die richtige Abfrage, die keine Ergebnisse, so dass es dann-Abfragen für alle passenden Datensätze zurückgegeben statt:
irb(main):001:0> Activity::MediaGroup.test_fail
Activity::MediaGroup Load (0.0ms) SELECT "activity_media_groups".* FROM "activity_media_groups" WHERE (1 = 0) ORDER BY "activity_media_groups"."id" ASC LIMIT 1
Activity::MediaGroup Load (0.0ms) SELECT "activity_media_groups".* FROM "activity_media_groups"
=> #<ActiveRecord::Relation [#<Activity::MediaGroup id: 1, created_at: "2014-01-06 01:00:06", updated_at: "2014-01-06 01:00:06", user_id: 1>, #<Activity::MediaGroup id: 2, created_at: "2014-01-06 01:11:06", updated_at: "2014-01-06 01:11:06", user_id: 1>, #<Activity::MediaGroup id: 3, created_at: "2014-01-06 01:26:41", updated_at: "2014-01-06 01:26:41", user_id: 1>, #<Activity::MediaGroup id: 4, created_at: "2014-01-06 01:28:58", updated_at: "2014-01-06 01:28:58", user_id: 1>]>
Den anderen Bereich arbeitet wie erwartet:
irb(main):002:0> Activity::MediaGroup.test_pass
Activity::MediaGroup Load (1.0ms) SELECT "activity_media_groups".* FROM "activity_media_groups" WHERE (1 = 1) ORDER BY "activity_media_groups"."id" ASC LIMIT 1
=> #<Activity::MediaGroup id: 1, created_at: "2014-01-06 01:00:06", updated_at: "2014-01-06 01:00:06", user_id: 1>
Wenn ich dieser Logik außerhalb eines Bereichs, bekomme ich die erwarteten Ergebnisse:
irb(main):003:0> Activity::MediaGroup.where('1=0').first
Activity::MediaGroup Load (0.0ms) SELECT "activity_media_groups".* FROM "activity_media_groups" WHERE (1=0) ORDER BY "activity_media_groups"."id" ASC LIMIT 1
=> nil
Bin ich hier etwas fehlt? Dies scheint ein bug in Rails/ActiveRecord/Scopes zu mir, es sei denn, es gibt einige unbekannten Verhaltens Erwartungen, ich bin bewusst.
.first
die Rückgabe eines Datensatzes, nicht eine ARel, richtig?- welche version von ruby und rails verwenden Sie ?
- Rails 4 und Ruby 2.0
- Ja, sollte es wieder eine Aufzeichnung und nicht eine ARel, aber wie Sie sehen können, wenn es nicht eine Aufzeichnung der Geltungsbereich nicht alle Datensätze zurück, die in der ARel
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dies ist kein bug oder Verrücktheit, nach einigen Recherchen habe ich gefunden gestaltet Zweck.
Zunächst
Den
scope
gibt einActiveRecord::Relation
Wenn es null Datensätze, Ihren programmierten alle Datensätze zurück
das wird wieder ein
ActiveRecord::Relation
stattnil
Die Idee dahinter ist, machen Bereiche verkettbare (ich.e) eine der wesentlicher Unterschied zwischen
scope
undclass methods
Beispiel:
Können verwenden Sie das folgende Szenario: der Benutzer wird in der Lage sein zu filtern Beiträge, die durch den Status der Bestellung nach dem neuesten aktualisierten ersetzt. Einfach genug, können Schreibbereiche für das:
Und wir nennen Ihnen frei, wie diese:
Oder mit einem Benutzer zur Verfügung gestellt param:
So weit, So gut. Nun verschieben Sie Sie in der Klasse-Methoden, nur für die Zwecke des Vergleichs:
Außerdem mit ein paar zusätzlichen Zeilen, keine große Verbesserungen. Aber was passiert nun, wenn die : "status" - parameter ist null oder leer?
Oooops, ich glaube nicht, dass wir wollten, um diese Abfragen ermöglichen, haben wir? Mit Fernrohren können wir leicht beheben, indem man einen Präsenz-Zustand zu unserem Umfang:
Weiter geht es:
Genial. Nun laßt uns versuchen, das gleiche zu tun mit unserem geliebten Klasse Methode:
Auszuführen:
Und :bomb:. Der Unterschied ist, dass der Umfang wird immer wieder eine Beziehung zu haben, in der Erwägung, dass unsere einfach Klasse, Methode, Umsetzung nicht. Methode die Klasse sollte wie folgt Aussehen statt:
Beachten Sie, dass ich zurückkehren werde alle für die null/leer-Fall, der in Rails 4 gibt eine relation (die es vorher zurückgegebene Array der Elemente aus der Datenbank). In Rails 3.2.x verwenden, sollten Sie den Gültigkeitsbereich dort statt. Und dann geht es Los:
So dass die Beratung hier ist: nie wieder null aus eine Klasse Methode, die sollte funktionieren wie ein Rahmen, sonst brechen die verkettbarkeit Bedingung impliziert Bereiche, dass immer wieder ein Bezug.
Lange Geschichte Kurz:
Egal was, Bereiche bestimmt sind, zurück
ActiveRecord::Relation
zu machen, verkettbare. Wenn Sie erwarten, dassfirst
,last
oderfind
Ergebnisse, die Sie verwenden solltenclass methods
Quelle: http://blog.plataformatec.com.br/2013/02/active-record-scopes-vs-class-methods/
scoped
stattall