domingo, 6 de dezembro de 2009

Associações polimórficas com Ruby on Rails

Hoje vou falar de um recurso que utilizei bastante nos últimos dias nos projetos que estou envolvido e acredito que seja útil para muitos.

O polimorfismo é uma características que existe em muitas linguagens orientadas a objetos, quando falamos de uma associação polimórfica, estamos dizendo que um objeto tem um outro objeto (ou mais), e esse outro objeto pode ser de várias formas (classes) diferentes.

Por exemplo:

Um objeto do tipo Tabuleiro (xadrez) tem muitas Peças, e essas peças podem ser de várias classes diferentes (Peão, Bispo, Torre, etc...).

Um exemplo na prática, digamos que existe a classe BankAccount (conta corrente) em sua aplicação Rails.

Essa BankAccount pertence a alguém, mas esse alguém pode ser um fornecedor (Supplier), um cliente (Customer) ou até mesmo um usuário (User).

Para lidarmos com esse tipo de situação no Ruby e persistir essas informações no banco de dados em uma aplicação Rails, podemos fazer da seguinte forma:

Primeiro passo: Definir um nome para essa associação

Nossa conta corrente pertence a qualquer objeto apto a ter uma conta corrente, vou chamar esse tipo de objeto de "accountable".

Segundo passo: Criar as colunas no banco de dados

Temos que criar duas colunas no banco de dados, uma que registrará o tipo do objeto (nome da classe) e outra o id do objeto.

Para criar essas colunas em uma migração, basta escrevermos assim:



Como visto na linha 9, a síntaxe é:

t.references :accountable, :polymorphic => true

Ou você pode criar manualmente duas colunas, uma com o nome da associação mais "_id" do tipo integer, e outra com o nome + "_type" do tipo string, como no exemplo:



Terceiro passo: configurar a classe BankAccount

Para definir a associação na classe BankAccount, fazemos assim:



Como visto na imagem:

belongs_to :accountable, :polymorphic => true

Quarto passo: configurar as classes que possuirão contas corrente

Para fazer isso, basta definirmos a associação nas classes que desejamos que possuam contas corrente, por exemplo, na classe Supplier:



Como mostrado na imagem, para definir a associação:

has_many :bank_accounts, :as => :accountable

Último passo: Utilizar onde for preciso

Uma vez configurada, para utilizar é muito simples, por exemplo, para dizer a uma conta que ela pertence a um usuário:

account.accountable = user

(supondo que a variável user está carregada com um objeto do tipo User)

Digamos que a conta pertence a um Supplier, e você deseja ver a razão social desse fornecedor:

account.accountable.corporate_name

Você pode também, a partir do objeto user ou qualquer outro objeto que possua a associação, recuperar um array de contas a partir de:

user.bank_accounts

Concluindo

Você pode estudar mais a respeito desse tipo de associação no Rails Guide.

Espero ter ajudado, qualquer dúvida pode postar um comentário ou entrar em contato via twitter, gtalk, e-mail, etc.