Named scopes w ActiveRecord 3

Posted by wijet
on Thursday, April 02

Od railsów 2.x możemy korzystać z dobrodziejstw named_scopes, za pomocą których możemy definiować w łatwy sposób findery. Mowiąc prościej, możemy budować zapytania do bazy danych. Nie są to jednak zwykłe metody ktore wyszukują nam coś w bazie, zamiast prostego zbioru wyników, zwracany jest scope (zakres).

Aby rzucić więcej swiatła na sprawę, zacznijmy od przykładu:

class Product < ActiveRecord::Base
  named_scope :available, :conditions => "amount > 0"
  named_scope :featured, :conditions => {:featured => true}
end

Pierwszy argument to nazwa scopu, drugi to hash taki jak przyjmuje metoda :find, albo lambda która zwraca taki hash. Mozemy także wywołać named_scope z blokiem, ale o tym poźniej.

Product.available
# SELECT * FROM "products" WHERE (amount > 0)

Product.featured
# SELECT * FROM "products" WHERE ("products"."featured" = 't') 

No tak, w sumie mozna by napisac "normalne" metody klasy, ktore zrobia to samo.

Wygladało by to tak:

def self.available
  all(:conditions => ["amount > 0"])
end

def self.featured
  all(:conditions => {:featured => true})
end

Dlaczego więc warto stosować named_scopes, zamiast "normalnych" metod ?

  • Ładniejszy, krótszy kod
  • Mozliwość łaczenia scopów

Łaczenie scopów

Tak, scopy mozemy łaczyć. Aby pobrać produkty, które są dostępne i promowane, napiszemy:


Product.available.featured
# SELECT * FROM "products" WHERE (("products"."featured" = 't') AND (amount > 0))

Jak widac, zostało wykonane jedno zapytanie, a warunki obu scopów zostały połączone.

Scopy które przyjmują argumenty

class Product < ActiveRecord::Base
  named_scope :limit, lambda { |limit| {:limit => limit} }
end

Wystarczy aby lambda zwracała hash opcji wyszukiwania, taki jak przekazujemy do metody :find.

Product.available.limit(20)

Anonimowy scope

Za pomocą metody scoped, moźemy tworzyć anonimowe scopy.

Product.scoped(:conditions => "name ~* 'tv'").limit(100)

Nie zaleca się jednak stosowania tego typu konstrukcji gdzie popadnie, gdyż możemy poprostu napisać scope nazwany w modelu, tam gdzie powinnismy trzymac nasze zapytania.

Są miejsca gdzie przydaje się anonimowy scope, tutaj jest przykład ciekawego wykorzystania Railscasts - Anonymous Scopes

Rozszerzenia dla named_scopes

Podobnie jak w przypadku associacji, możemy tworzyć rozszerzenia dla scopów. Dodajmy metode która zamówi wszystkie produkty, których brakuje.

named_scope :unavailable, :conditions => {:amount => 0} do
  def order
    each { |product| Order.create(:product => product) }
  end
end
Product.unavailable

Zwraca wszystkie produkty ktorych brakuje

natomiast

Product.unavailable.order

Tworzy zamowienia, dla kazdego z tych produktów.

Rails 2.3

W railsach 2.3 został wprowadzony scope dynamiczny i domyslny.

Dynamiczny scope

Możemy używac dynamicznych scopow, podobnie jak dynamiczynych finderow, czyli:

Product.scoped_by_amount_and_featured(100, true)

Domyślny scope

Nastepną bardzo użyteczna konstrukcją, jest możliwość zdefiniowania domyślnego scopu dla modelu. Bardzo często konkretna tabele sortujemy po konkretnej kolumnie/kolumnach.

class Product < ActiveRecord::Base
  default_scope :order => "name DESC"
end

Przydaje się też, gdy chcemy ukryc pewne rekordy, np. produkty które nie są aktualnie odstępne:

default_scope :conditions => "amount > 0"

Linki

Module ActiveRecord::NamedScope::ClassMethods

Railscasts named_scope

What's New in Edge Rails: Has Finder Functionality

What's New in Edge Rails: Default Scoping

What's New in Edge Rails: Dynamic Scope Methods

Comments

Leave a response

  1. SebanApril 30, 2009 @ 07:30 AM

    named_scope pojawiły się 2.1.0.
    default_scope do mnie nie przemawia, szczególnie przypadek z conditions => “amount > 0”. Dynamiczny scope też wydaje mi się trochę naciągany na siłe, np. Product.scoped_by_amount_and_featured_and_sth_and_another_and_pretty_code(100, true, true,true, false) trąci mi jakimś masochizmem i bałaganiarstwem

  2. wijetApril 30, 2009 @ 11:52 AM

    Dzieki, juz poprawiam. Co do default scope to uwazam ze jest bardzo uzyteczna konstrukcja, bardzo czesto sortuje konkretne modele, i czesto jej uzywam, moze ten przyklad z amount taki sredni. A z tym dynamicznym scopem, to tak jak z alkoholem, trzeba znac umiar :)

  3. onlineDecember 22, 2009 @ 07:23 PM

    nauczylem sie bardzo wiele

Comment