Active Record em: Como adicionar comportamento as suas associações

Posted by Roger Leite on maio 19, 2010

Qualquer um que comece a desenvolver com Active Record (AR), minha primeira recomendação é, para tudo e leia:  A Guide to Active Record Associations ou O Guia de Associações do Active Record. O guia é bem completo, e descreve muito bem os tipos de associações que estão disponíveis no AR.

Association Proxy, #wtf !

As associações:

  • belongs_to
  • has_one
  • has_many
  • has_and_belongs_to_many

Quando usadas, adicionam alguns métodos (veja Detailed Association Reference). Por exemplo, ao declarar uma associação belongs_to, o model “ganhará” os seguintes métodos:

  • association(force_reload = false)
  • association=(associate)
  • build_association(attributes = {})
  • create_association(attributes = {})

Onde association, será substituído pelo nome da associação. Exemplo retirado do guides:

class Order < ActiveRecord::Base
   belongs_to :customer
end

Cada instância de Order, conterá os métodos:

  • customer
  • customer=
  • build_customer
  • create_customer

O association proxy, é o objeto que faz a ligação do objeto que contém a associação, conhecido como owner, e o objeto associado, conhecido como target.

Legal e daí !?!

Graças ao association proxy, ao declarar uma associação, podemos extendê-la e adicionar comportamentos “customizados”. No guia, é citado como Association Extensions. O código de exemplo abaixo, está no github em random-samples.

Para exemplificar, vamos criar um modulo que adiciona o comportamento de uma galeria a qualquer coleção.

module GalleryColletion
 
  def current=(curr = nil)
    @current, @index = nil
 
    if curr.nil?
      @current = collection.first
      @index = 0
    else
      collection.each_with_index do |item, index|
        if item.id.to_i == curr.to_i
          @current = item
          @index = index
        end
      end
    end
    @current
  end
 
  def current
    @current
  end
 
  def position
    @index + 1
  end
 
  def previous?
    return false if @index.nil?
    !!(@index - 1 >= 0)
  end
  def previous
    collection[@index - 1] if previous?
  end
 
  def next?
    return false if @index.nil?
    !!(@index + 1 < collection.size)
  end
  def next
    collection[@index + 1] if next?
  end
 
  private
 
  def collection
    proxy_owner.send(proxy_reflection.name)
  end
 
end

Gallery Collection

Note que o modulo está na pasta lib, logo, a pasta tem que ser adicionada no path via config/environment.rb.

Para extender a associação, declare:

class Article < ActiveRecord::Base
  has_and_belongs_to_many :images, :extend => GalleryColletion
end

Article model, Image model aqui.

Agora para navegar entre as imagens, você pode usar:

a = Article.first
a.images.current = 1 #1 e o Image.id que deseja selecionar
a.images.current
a.images.position
a.images.next?
a.images.next
a.images.previous?
a.images.previous

Caso esteja com coragem, baixe o projeto e veja rodando.

Dúvidas, sugestões, algum “case” de sucesso, comente!

Trackbacks

Use this link to trackback from your own site.

Comments

Leave a response

Comments