Active Record Associations en Ruby on Rails

Has Many Associations

Ejemplo: Posts a Comentarios

Paso 1: Creamos los modelos

bin/rails g model Comment content:text name:string

bin/rails g model Post body:text title:string

Paso 2: Realizamos la migración

bin/rails db:migrate

Paso 3: Actualizamos el modelo Post


class Post < ApplicationRecord
has_many :comments
end

Paso 4: Añadimos la columna post_id a la tabla/modelo Comments

bin/rails generate migration AddPostToComments post_id:integer:index

Esto creará la siguiente migración:

class AddPostToComments < ActiveRecord::Migration[5.0]
def change
add_column :comments, :post_id, :integer
add_index :comments, :post_id
end
end

Es muy recomendable que cada vez que establezcamos una asociación del tipo Has Many también establezcamos una asociación belongs_to en el segundo modelo. Realmente no es necesario ya que podemos hacer

Post.find(comment.post_id)
pero puede ser más fácil del tipo 
comment.post
. Para ello tenemos que editar el modelo de Comments y añadir una propiedad belongs_to

class Comment < ApplicationRecord
belongs_to :post
end

Foreign Key required by our has_many and Belongs_to associations


bin/rails generate migration AddPostToComments post:references

 

 

Esto generará un archivo de migración con el método de add_reference en lugar del add_colum. El método add_references crearé una columna con el nombre del modelo seguido por _id y también creará una columna de id. En resumen,

add_reference :comments, :post
creará una columna post_id in la tabla comments.

The

foreign_key: true
creará una foreign_key en las databases que lo soporten. rails utiliza la base de datos SQLite y no soporta foreign key.

Crear la asociación con el la creación del Model simultáneamente

Si sabemos que nos hará falta una asociación cuando estamos creando un modelo

bin/rails g model Comment content:text name:string post:references
bin/rails db:migrate

 

Has and Belongs to Many Associations

Ejemplo: Users and Forums

Necesitamos crear una tabla adicional para almacenar esta asociación

Paso 1: Creamos los modelos

Paso 2:Creamos la tabla JOIN

bin/rails g migration CreateJoinTableUsersForums users forums

Archivo de migración creado


class CreateJoinTableUsersForums < ActiveRecord::Migration[5.0]
def change
create_join_table :users, :forums do |t|
t.index [:user_id, :forum_id] #uncomment this
t.index [:forum_id, :user_id] #uncomment this
end
end
end

ActiveRecord no sabe usar la tabla Join para asociar los dos modelos, Tenemos que añadir el atributo has_and_belongs_to_many a ambos modelos.


class User < ApplicationRecord
has_and_belongs_to_many :forums
end

class Forum < ApplicationRecord
has_and_belongs_to_many :forums
end

Ahora podemos añadir forums a un usuario

user.forums << Forum.find_by(name: "Ruby")

y También podemos buscar usuarios que pertenezcan a un Forum:

Forum.find_by(name: "Ruby").users

Has Many Through Associations

Ejemplo: Suscribers and Magazines. Queremos que los suscribers se suscriban a magazines pero con información adicional en la tabla Join,  como por ejemplo cuántos meses están suscritos (column months). Esta nueva tabla reprensenta un nuevo modelo.

Paso 1: Lo primero que necesitamos hacer es generar la tabla JOIN nueva

bin/rails g model Subscription months:integer subscriber_id:integer magazines_id:integer

Paso 2: Actualizar los tres modelos con las asociaciones


class Subscription < ApplicationRecord
belongs_to :subscriber
belongs_to :magazine
end


class Subscriber < ApplicationRecord
has_many :subscriptions
has_many :magazines, through: :subscriptions
end

class Magazine < ApplicationRecord
has_many :subscriptions
has_many :subscribers, through: :subscriptions
end

Paso 3: Realizar la migración

Has One Associations

Ejemplo: Users and Profile

Funciona igual que una asociación has_many pero en  la referencia en la tabla original sólo está enlazada con una sola refenrencia en la segunda tabla.

Paso 1: Creamos el modelo

bin/rails g model Profile user:references twitter:string github:string

Paso 2: realizamos la migración

Paso 3: Modificamos el modelo


class User < ApplicationRecord has_and_belongs_to_many :forums has_one :profile end [/code]