Associações – ActiveRecord
Este guia aborda as características de associação do ActiveRecord. Ao fazer referência a este guia, você será capaz de:
· Declarar associações entre os Models do ActiveRecord.
· Compreender os diferentes tipos de associações do ActiveRecord.
· Utilizar os métodos adicionados aos seus modelos através das associações criadas.
1. Associações, Por quê?
Por que precisamos de associações entre os modelos? Porque tornam mais fácil e mais simples operações comuns no código. Considere, por exemplo, uma simples aplicação Rails que inclui um modelo para os clientes e um modelo para as encomendas. Cada cliente pode ter muitas encomendas. Sem as associações, os modelos de declarações seriam mais ou menos assim:
class Customer < ActiveRecord::Base end class Order < ActiveRecord::Base end
Agora, suponha se quisesse acrescentar uma nova encomenda de um cliente existente. Gostaríamos de fazer algo parecido com isto:
@order = Order.create(:order_date => Time.now, :customer_id => @customer.id)
Ou apagar um cliente, e garantindo que todas as suas ordens fossem excluídas também:
@orders = Order.find_by_customer_id(@customer.id) @orders.each do |order| order.destroy end @customer.destroy
Com as associações do ActiveRecord, que podemos simplificar – e outras – operações por declarações dizendo que existe uma conexão entre os dois modelos. Veja abaixo o código revisado para a criação de clientes e encomendas:
class Customer < ActiveRecord::Base has_many :orders end class Order < ActiveRecord::Base belongs_to :customer end
Com essa mudança, criando uma nova ordem para um determinado cliente é mais fácil:
@order = @customer.orders.create(:order_date => Time.now)
Excluindo um cliente e todas as suas encomendas é muito mais fácil:
@customer.destroy
Para saber mais sobre os diferentes tipos de associações, leia a próxima seção deste Guia. Seguido por alguns truques e dicas para trabalhar com as associações e, em seguida, por uma referência completa para os métodos e opções para as associações em Rails.
2. Os tipos de associações
Em Rails, uma associação é uma conexão entre os dois modelos do ActiveRecord. As associações são implementadas usando macro de chamadas, de modo que você pode adicionar funcionalidades nos seus modelos. Por exemplo, declarando que um modelo possui belongs_to com outro, você instrui o Rails a manter as informações de Chave Primária entre instâncias dos dois modelos, e você também receberá um número métodos úteis adicionado ao seu modelo. Rails suporta seis tipos de associação:
* belongs_to * has_one * has_many * has_many :through * has_one :through * has_and_belongs_to_many
No restante deste guia, você aprenderá a declarar e utilizar as diversas formas de associações. Mas, primeiro, uma introdução rápida a situações em que cada tipo de associação é adequado.
2.1. A Associação belongs_to
Uma associação belongs_to cria uma conexão um-para-um com outro modelo, de modo a que cada instância do modelo com a declaração “pertence a” uma instancia de um outro modelo. Por exemplo, se sua aplicação incluir clientes e encomendas, e cada encomenda pode ser atribuído por exatamente um cliente, você declararia o modelo desta forma:
class Order < ActiveRecord::Base belongs_to :customer end
2.2. A Associação has_one
A associação has_one também prevê a criação de uma conexão um-para-um com outro modelo, mas com uma semântica um pouco diferente (e conseqüências). Esta associação indica que cada instância de um modelo contém ou possui uma instancia de outro modelo. Por exemplo, se cada um fornecedor na sua aplicação possui somente uma conta, você iria declarar o modelo fornecedor como este:
class Supplier < ActiveRecord::Base has_one :account end
2.3. A Associação has_many
Uma associação has_many indica uma conexão um-para-muitos com outro modelo. Você irá encontrar muitas vezes esta associação do “outro lado” de uma associação belongs_to. Esta associação indica que cada instância do modelo possui nenhuma ou mais instancias do outro modelo. Por exemplo, em uma aplicação contendo clientes e encomendas, o modelo cliente deve ser declarado como este:
class Customer < ActiveRecord::Base has_many :orders end
O nome do outro modelo é pluralizado quando declarado uma associação has_many.
2.4. A Associação has_many :through
Um associação has_many :through é freqüentemente utilizado para criar um conexão muitos-para-muitos com outro modelo. Esta associação indica que a declaração do modelo possa ser compensada com zero ou mais instancias de outro modelo “através de” um processo de um terceiro modelo. Por exemplo, considere uma prática médica onde pacientes podem marcar para ver médicos. As declarações relevantes da associação devem ser semelhantes a este:
class Physician < ActiveRecord::Base has_many :appointments has_many :patients, :through => :appointments end class Appointment < ActiveRecord::Base belongs_to :physician belongs_to :patient end class Patient < ActiveRecord::Base has_many :appointments has_many :physicians, :through => :appointments end
O associação has_many :through é também útil para a criação de “atalhos” através de associações has_many aninhadas. Por exemplo, se um documento tem muitas seções, e uma seção possui muitos parágrafos, você pode algumas vezes pegar uma simples coleção de todos os parágrafos no documento. Você poderia declarar desta forma:
class Document < ActiveRecord::Base has_many :sections has_many :paragraphs, :through => :sections end class Section < ActiveRecord::Base belongs_to :document has_many :paragraphs end class Paragraph < ActiveRecord::Base belongs_to :section end
2.5. A Associação has_one: through
Uma associação has_one :through cria uma conexão de um-para-um com outro modelo. Esta associação indica que a declaração do modelo possa ser combinada com uma instancia de outro modelo através de um terceiro modelo. Por exemplo, se cada fornecedor possui uma conta, e cada conta está associada a um histórico da conta, então o modelo cliente poderá ser declarado desta forma:
class Supplier < ActiveRecord::Base has_one :account has_one :account_history, :through => :account end class Account < ActiveRecord::Base belongs_to :supplier has_one :account_history end class AccountHistory < ActiveRecord::Base belongs_to :account end
2.6. A Associação has_and_belongs_to_many
Uma associação has_and_belongs_to_many cria uma conexão direta muitos-para-muitos com outro modelo, sem intervir no modelo. Por exemplo, se a sua aplicação incluir peças e conjuntos, onde cada conjunto inclui várias peças e que cada peça aparece em muitos conjuntos, você poderia declarar os modelos desta maneira:
class Assembly < ActiveRecord::Base has_and_belongs_to_many :parts end class Part < ActiveRecord::Base has_and_belongs_to_many :assemblies end
2.7. Escolhendo Entre belongs_to e has_one
Se você deseja criar uma relação 1×1 entre dois modelos, será necessário adicionar a um belongs_to e ao outro has_one. Como você sabe quem é quem?
A distinção está no lugar onde você colocou a chave estrangeira (ele fica na tabela da classe que foi declarada a associação belongs_to), mas você deveria refletir um pouco mais sobre o real significado desses dados. O relacionamento has_one fala alguma coisa para os seus – ou seja, algo que aponta de volta para você. Por exemplo, faz mais sentido dizer que um fornecedor possui uma conta do que uma conta que possui um fornecedor. Isso sugere que o relacionamento correto é algo como este:
class Supplier < ActiveRecord::Base has_one :account end class Account < ActiveRecord::Base belongs_to :supplier end
A migração correspondente se parece com isso:
class CreateSuppliers < ActiveRecord::Migration
def self.up
create_table :suppliers do |t|
t.string :name
t.timestamps
end
create_table :accounts do |t|
t.integer :supplier_id
t.string :account_number
t.timestamps
end
end
def self.down
drop_table :accounts
drop_table :suppliers
end
end
Usando t.integer :supplier_id faz a nomeação da chave estrangeira óbvia e implicitamente. Nas versões atuais do Rails, você pode abstrair a implementação deste detalhe usando t.references :supplier.
2.8. Escolhendo Entre has_many :through e has_and_belongs_to_many
Rails oferece duas maneiras diferentes para declarar um relacionamento um-para-muitos entre modelos. A maneira mais simples é usar has_and_belongs_to_many, que permite que você faça a associação diretamente:
class Assembly < ActiveRecord::Base has_and_belongs_to_many :parts end class Part < ActiveRecord::Base has_and_belongs_to_many :assemblies end
A segunda forma de declarar o relacionamento muitos-para-muitos é usar has_many :through. Isto faz com que crie uma associação indiretamente, através de um join no modelo:
class Assembly < ActiveRecord::Base has_many :manifests has_many :parts, :through => :manifests end class Manifest < ActiveRecord::Base belongs_to :assembly belongs_to :part end class Part < ActiveRecord::Base has_many :manifests has_many :assemblies, :through => :manifests end
A regra é simples, você deve criar um relacionamento has_many :through se você precisa trabalhar com o relacionamento do modelo como uma entidade independente. Se você não precisa fazer nada com relacionamento do modelo, pode ser mais simples se criar um relacionamento has_and_belongs_to_many (mas você precisa se lembrar se precisa criar joins nas tabelas).
Você deve usar has_many :through se você precisar de validações, callbacks (chamadas), ou atributos extras no join do modelo.
2.9. Associações polimórficas
Um pouco mais avançado é o twist em associações polimórficas. Com associações Polimórficas, um modelo pode pertencer a mais de um modelo, em uma única associação. Por exemplo, imagine que você possa ter um modelo foto que pertence a um empregado ou ao modelo produto. Veja como isso poderia ser declarada:
class Picture < ActiveRecord::Base belongs_to :imageable, :polymorphic => true end class Employee < ActiveRecord::Base has_many :pictures, :as => :imageable end class Product < ActiveRecord::Base has_many :pictures, :as => :imageable end
Você pode pensar em uma declaração belongs_to polimórfica criando uma interface que pode ser usada por qualquer outro modelo. A partir de uma instância do modelo Employee, você pode recuperar uma coleção de fotos: @employee.pictures. Da mesma forma, você pode usar @product.pictures. Se você tem uma instancia do modelo Picture você pode pegar seu pai através @picture.imageable. Para que isto funcione, você necessita declarar tanto uma coluna chave estrangeira e uma coluna tipo no modelo declarado com uma interface polimórficas:
class CreatePictures < ActiveRecord::Migration
def self.up
create_table :pictures do |t|
t.string :name
t.integer :imageable_id
t.string :imageable_type
t.timestamps
end
end
def self.down
drop_table :pictures
end
end
Esta migração pode ser simplificada utilizando o formulário t.references:
class CreatePictures < ActiveRecord::Migration
def self.up
create_table :pictures do |t|
t.string :name
t.references :imageable, :polymorphic => true
t.timestamps
end
end
def self.down
drop_table :pictures
end
end
2.10. Self Joins
Na criação de um modelo de dados, às vezes você irá encontrar um modelo que deverá ter uma relação a si própria. Por exemplo, você pode armazenar todos os empregados em uma única base de dados, mas ser capaz de rastrear relacionamentos como gerentes e subordinados. Esta situação pode ser modelada com as associações com ele mesmo:
class Employee < ActiveRecord::Base has_many :subordinates, :class_name => "User", :foreign_key => "manager_id" belongs_to :manager, :class_name => "User" end
Com essa configuração, você pode utilizar @employee.subordinates e @employee.manager.
Créditos:
Link Conteúdo Original: http://guides.rails.info/association_basics.html
Tradução: Herminio Torres. [ http://hidenowt.wordpress.com ]
Revisão: Cairo Noleto. [ http://www.caironoleto.com ]

