Notas sobre Ruby e Rails.

associacoes.md 4.2KB

Associações

Para interligar tabelas atravez dos "forein_keys", criamos associações enre os modelos.

Existem 3 tipos de associações: 1 para 1, 1 para varios e varios para varios.

1 para 1

Tipo de associação de um objeto para outro. Util para quebrar uma tabela grande em varias partes. Sempre defina os dois lados da associação!

Exemplo

  • subject-page
    • Page has_one :subject
    • Subject has_one :page

No modelo Subject:

class Subject < ActiveRecord::Base
    has_one :page
end

No modelo Page:

class Page < ActiveRecord::Base
    has_one :subject, {:foreign_key => "subject_id"}
end

Para utilizar as associações, carregue um objeto e chame o metodo associado para ter o objeto retornado:

subject.page ou page.subject

1 para varios

As associações de um objeto para varios são muito usadas dentro dos aplicativos em rails. Elas utilizm o termo no plural e retornam um array de objetos.

A classe com o belongs_to que deve ter o foreign key

Exemplo

  • user-photos
    • User has_many :photos
    • Photo belongs_to :user

No modelo User:

class User < ActiveRecord::Base
    has_many :photos
end

No modelo Photo:

class Photo < ActiveRecord::Base
    belongs_to :user
end

Metodos

  • user.photos
  • user.photos << photo
  • user.photos = [photo, photo, photo]
  • user.photos.delete(photo)
  • user.photos.clear
  • user.photos.empty?
  • user.photos.size
  • user.photos[1]

varios para varios

Este tipo de associação é utilizada quando um objeto está associado a varios outros objetos, mas não exclusivamente.

Para este tipo de associação, primeiro é necessario criar uma join table, ou seja, uma tabela simples que não tem um primary key e tem apenas duas colunas com os ids dos dois objetos das duas tableas sendo relacionados.

Join Table

A nova tabela que vai guardar as inforamções da associação tem algumas regras de nomeação especificas:

  • Primeira_tabela + _ + segunda_tabela
  • Os dois nomes são no plural
  • Os nomes entram em ordem alfabetica
  • Nome default que pode ser configurado

Exemplo

  • posts-tags
    • Post has_and_belongs_to_many :tags
    • Tags has_and_belongs_to_many :posts

O nome da tabela vai ser: "posts_tags".

1 - Criar o arquivo de migração:

rails generate migration CreatePostsTagsJoin

2 - Editar o arquivo de migração:

class CreatePostsTagsJoin < ActiveRecord::Migration
    def self.up
      create_table :posts_tags, :id => false do |t|
        t.integer "post_id"
        t.integer "tag_id"
      end
      add_index :posts_tags, ["post_id", "tag_id"]
    end
    def self.down
      drop_table :posts_tags
    end
end

3 - Rodar a migração:

rake:db:migrate

4 - No arquivo do modelo Post:

class Post < ActiveRecord::Base
    has_and_belongs_to_many :tags
end

5 - No arquivo do modelo Tag:

class Tag < ActiveRecord::Base
    has_and_belongs_to_many :blog_posts, :class_name => "Post" 
end

Associações Avançadas

Outra maneira de fazer associações de varios objeos para varios outros é criando um modelo proprio para administrar essas associaçãos e outras informações.

A diferença é que a tabela precisa de um primary key e não precisa seguir nenhuma conveção para o nome.

Exemplo

Neste exemplo vamos criar um log de edição das páginas do sistema.

  • User has_many :page_edits
  • PageEdit belongs_to :user
  • Page has_many :page_edits
  • PageEdit belongs_to :page

1 - Criar um modelo:

rails generate model PageEdit

2 - Editar o arquivo de migração:

class CreatePageEdits < ActiveRecord::Migration
    def self.up
      create_table :posts_tags do |t|
        t.references :page
        t.references :user
        t.string "new_content"
        t.timestamps
      end
      add_index :page_edits, ["page_id", "user_id"]
    end
    def self.down
      drop_table :posts_tags
    end
end

3 - Rodar a migração:

rake:db:migrate

4 - No arquivo do modelo Page:

class Page < ActiveRecord::Base
    has_many :page_edits
end

5 - No arquivo do modelo User:

class User < ActiveRecord::Base
    has_many :page_edits
end

6 - No arquivo do modelo PageEdit:

class User < ActiveRecord::Base
    belongs_to :page
    belongs_to :editor, :class_name => "User", :foreign_key => "user_id"
end

Traversing