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”

  1. Pedro Pimentel on July 30th, 2008 00:43

    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

  2. Lucas Húngaro on July 30th, 2008 02:23

    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.

  3. Philipe Farias on July 30th, 2008 11:15

    O shoulda já conta com um helper pra named_scopes:

    http://giantrobots.thoughtbot.com/2008/7/29/testing-named_scope

  4. Lucas Húngaro on July 30th, 2008 12:03

    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!

  5. Weldys Santos on August 8th, 2008 15:50

    Pô Lucas, o post tá show de bola hein! Named scopes realmente é mão na roda pra desenvolver regras pra buscas

  6. Lucas Húngaro on August 8th, 2008 16:47

    Valeu Weldys! Pô, nem linkaram no Rails Podcast. ;)

Leave a Reply