2009-08-10 12 views
7

Załóżmy mam nazwanego zakresu:Sprawdź, czy instancja modelu objęta named_scope w szynach

class Foo < ActiveRecord::Base 
    named_scope :bar, :conditions => 'some_field = 1' 
end 

Działa to wielkie dla zapytań i mam kilka przydatnych named_scopes zdefiniowane. Chciałbym móc to zrobić:

f = Foo.find(:first) 
f.some_field = 1 
f.is_bar? #=> true 

".bar?" metoda po prostu zwróci true lub false, jeśli instancja modelu mieści się w nazwanym zakresie. Czy mimo to można to zrobić bez pisania "is_bar?" metoda, mimo że już napisałem dobry sposób, aby sprawdzić, czy coś "jest_bar?" Jeśli dobrze pamiętam, DRY jest dobra, więc każda pomoc byłaby bardzo cenna/

Odpowiedz

20

Możesz wywołać metodę exists? na nazwanym zakresie, który przeszuka bazę danych, aby sprawdzić, czy dany rekord istnieje z tymi warunkami.

Foo.bar.exists?(f) 

Jednak to nie będzie działać, jeśli zostały zmienione atrybuty na f i nie zapisany w bazie danych. Dzieje się tak dlatego, że nazwanymi warunkami zakresu są SQL, więc sprawdzanie musi się tam odbyć. Próba konwersji na warunki Ruby if jest kłopotliwa, szczególnie w bardziej złożonych sytuacjach.

+0

dzięki. Ok, udaj, że zadzwoniłem. Zachowaj po zmianie wartości. Foo.bar.exists? (Foo.find (: first)) zwróci wartość true lub false w zależności od tego, czy mieści się ona w zasięgu kreski? Niesamowite. – user94154

+0

Prawidłowo. Nie powinieneś też zadzwonić ponownie do Find. "f.save; Foo.bar.exists? (f)" powinno działać. – ryanb

+4

Czy stało się to łatwiejsze od 2009 roku? –

1

Jeśli twoje zakresy są proste, prawdopodobnie chcesz uniknąć duplikowania kodu. Moje rozwiązanie pozwala zadzwonić pod numer model.active?, aby dowiedzieć się, czy instancja należy do zakresu, i Model.active, aby znaleźć wszystkie rekordy pasujące do zakresu. model.active? nie obejmuje żadnych zapytań do bazy danych.

rozważyć dodanie tego do config/initializers/scope_and_method.rb:

require 'active_record/named_scope' 

module ActiveRecord::NamedScope::ClassMethods 
    def scope_and_method field, *values 
    field = field.to_sym 
    values.each do |value| 
     named_scope value.to_sym, :conditions => {field => value} 
     define_method "#{value}?" do 
     send(field.to_sym) == value 
     end 
    end 
    end 
end 

Zastosowanie:

scope_and_method :state, 'active', 'inactive' 

Works jakby to było:

named_scope :active, :conditions => {:state => 'active'} 
named_scope :inactive, :conditions => {:state => 'inactive'} 

def active? 
    state == 'active' 
end 

def inactive? 
    state == 'inactive' 
end 

Jest to rozwiązanie dla Rails 2.3. To wymaga bardzo małego strojenia dla Railsów 3 i 4. (named_scope ->scope) Sprawdzę to wkrótce.