2016-05-13 4 views
2

Nach der Rails documentation for scope, ein Rahmen wie zum Beispiel:Warum kann diese bereichsähnliche Abfragemethode keine Zurückweisung verwenden?

class Shirt < ActiveRecord::Base 
    scope :red, -> { where(color: 'red') } 
end 

ist wirklich:

class Shirt < ActiveRecord::Base 
    def self.red 
     where(color: 'red') 
    end 
end 

Sie sagen auch, dass die Beziehung als Array handeln sollte, so etwas wie diese

tun
Shirt.red.each(&block) 

sollte funktionieren ... und es tut.

Mit allem, was wir oben wissen, warum funktioniert das folgende nicht?

class Shirt < ActiveRecord::Base 
    def self.short_sleeved 
     reject{|object| object.short_sleeved == false} 
    end 
end 

Shirt.red.short_sleeved Ergebnisse in undefined method 'reject' for #<Class:0xba552d4>

+0

Ich weiß nicht, was Sie zu tun versuchen? 'Klasse Shirt {wo (short_sleeve: true)} end' '' wird es tun – MZaragoza

+1

Laut APIDock sollte die Syntax ich hätte funktionieren sollen ... aber ich habe einen Thread gefunden auf der Schiene git Repository, das den gleichen Fehler gegeben hatte. Die Lösung besteht darin, alle dem Enumerator voranzustellen ... all.reject {} https://github.com/rails/rails/issues/21943 –

Antwort

1

Sie können die short_sleeved Methode, um die Art und Weise nicht definieren Sie versucht, weil Active Klassen sind nicht Beziehungen Active.

Sie haben short_sleeved auf Shirt definiert. Shirt ist eine ActiveRecord-Modellklasse. Es ist nicht selbst eine ActiveRecord-Beziehung. Es hat Methoden einschließlich all und where und viele andere, die ActiveRecord Beziehungen zurückgeben.

Wie die integrierten Abfragemethoden geben Bereiche ActiveRecord-Relationen zurück. Eine ActiveRecord-Beziehung hat eine dynamisch generierte Klasse. Es ist kein Enumerable sondern reagiert auf Enumerable Methoden:

red_shirts = Shirt.red 
red_shirts.class 
=> Shirt::ActiveRecord_Relation 
red_shirts.respond_to? :each 
=> true 
red_shirts.respond_to? :reject 
=> true 

So können Sie Ihre Methode, um diese Art und Weise schreiben könnte:

def self.short_sleeved 
    all.reject { |object| object.short_sleeved == false } 
end 

jedoch, dass lädt alle Shirt s aus der Datenbank und dann filtert im Speicher, die nicht so effizient ist für eine große Anzahl von Shirt s als die Filterung in der Datenbank mit where wie MZaragosa vorgeschlagen. Sie könnten das tun wie dieser

def self.short_sleeved 
    where short_sleeved: true 
end 

oder

scope :short_sleeved, -> { where short_sleeved: true } 
+1

Ich war gerade dabei, diese ausführliche Antwort zu schreiben, während du deine ... der Punktkommentar. Ich lasse es für den Fall, dass es für andere hilfreich ist. –

+0

Dies beantwortet meine Frage gründlich. Es ist wertvoll, dass Sie dies in nicht effizient, aber in meiner Situation, der letzte Bereich, den ich brauchte, ist nicht möglich mit einer einfachen Abfrage. Zu diesem Zeitpunkt werde ich eine kleine Liste haben, dass es "nie" ein Problem sein sollte. Vielen Dank! –