Um pouco mais sobre named_scopes
Um pouco mais? Mas cadê o primeiro artigo sobre isso? Bom, não o escrevi, mas vou partir do ponto em que parou o Nando Vieira em seu artigo sobre named_scopes. Logo, assumo que você já sabe o que é um named_scope e conhece algumas possibilidades, como condições dinâmicas e encadeamento de named_scopes.
Apenas lendo uma introdução aos named_scopes já dá pra ficar bem empolgado. É um recurso simples e, ao mesmo tempo, poderoso e, quando bem utilizado, pode resulta no código bonito e sucinto que buscamos todo dia.
Vamos, então, explorar mais algumas possibilidades desse recurso.
Modificadores para filtros
Além de estabelecer condições de filtro, podemos aplicar modificadores a eles. Um exemplo é aplicando ordenação:
class User < ActiveRecord::Base named_scope :boys, :conditions => ["gender = ?", 'M'] named_scope :girls, :conditions => ["gender = ?", 'F'] named_scope :created_since, lambda { |days| {:conditions => ["created_at >= ?", days]}} #modificando o filtro com ordenação named_scope :by_first_name, :order => "first_name ASC" end
Isso possibilita os seguintes usos:
User.girls.by_first_name User.boys.by_first_name #ou, somente: User.by_first_name #encadeando como se não houvesse amanhã e operando sobre o resultado! User.girls.created_since(5.days.ago).by_first_name.map(&:first_name)
Flexibilizando os escopos
Que tal um filtro aplicável a diferentes atributos do modelo? Vamos lá:
#adding the scope to ActiveRecord::Base so it's available to all models class ActiveRecord::Base named_scope :contains, lambda { |column, text| {:conditions => ["lower(#{column}) LIKE ?", "%#{text.downcase}%"]} } end
Utilizando:
User.contains(:first_name, "%mat%") User.contains(:last_name, "Sinclair") #encadeando... User.boys.contains(:last_name, "S%").by_first_name #enlouquecendo... User.girls.contains(:first_name, "Je%").created_since(5.days.ago).by_first_name.map(&:first_name)
Mesclando finders dinâmicos e escopos
User.boys.find_all_by_first_name("Peter")
Note que o finder deve ser o último método na cadeia, pois retorna um Array, onde seus escopos não existem:
=> User.find_all_by_first_name("A%").boys NoMethodError: undefined method `boys' for #<Array:0x21e7bf0>
Testando named_scopes
É claro que temos que testar se os escopos estão formando as condições da maneira que desejamos. Existem alguns métodos que ajudam a fazer isso:
should "correctly generate the 'boys' scope" do expected = {:conditions => ["gender = ?", "M"]} assert_equal(expected, User.boys.proxy_options) end
Observação: os exemplos são para ilustrar o que pode ser feito com esse recurso. Tome muito cuidado com os encadeamentos que executar, sempre observando as queries resultantes. Um pequeno deslize pode significar um gargalo significativo.
Leia mais:
More Named Scope Awesomeness
Comments
6 Responses to “Um pouco mais sobre named_scopes”
Leave a Reply

Realmente dá pra pirar muito com o escopo nomeado.
Eu só não entendo pq deram ao método “proxy_options” este nome, não significa muito pra mim…. Tu saberia me dizer o por quê ?
abraços
Pedro, numa pesquisa rápida não encontrei nada.
Por inferência, creio que seja o seguinte: o named_scope é um proxy para uma finder, isto é, um conjunto de opções (:conditions, :order, :limit etc) nomeado. Logo, proxy_options retorna as opções utilizadas nesse proxy.
Algo como scope_options provavelmente faria mais sentido.
O shoulda já conta com um helper pra named_scopes:
http://giantrobots.thoughtbot.com/2008/7/29/testing-named_scope
Muito legal! Eu gosto bastante do Shoulda e ia escrever esse helper. Escrevi o artigo antes de ver que tinha post novo no Giant Robots!
Valeu Philipe!
Pô Lucas, o post tá show de bola hein! Named scopes realmente é mão na roda pra desenvolver regras pra buscas
Valeu Weldys! Pô, nem linkaram no Rails Podcast.