Relaciones en Rails 3(1 1,1 n,n n)

64
Desarrollo web con Ruby on Rails 3 ActiveRecord: asociaciones entre clases Áncor González Sosa Imobach González Sosa Banot.net http://www.banot.net/ Octubre de 2010 Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 1 / 64

description

Rails

Transcript of Relaciones en Rails 3(1 1,1 n,n n)

Page 1: Relaciones en Rails 3(1 1,1 n,n n)

Desarrollo web con Ruby on Rails 3ActiveRecord: asociaciones entre clases

Áncor González Sosa Imobach González Sosa

Banot.nethttp://www.banot.net/

Octubre de 2010

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 1 / 64

Page 2: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 2 / 64

Page 3: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 3 / 64

Page 4: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 4 / 64

Page 5: Relaciones en Rails 3(1 1,1 n,n n)

Los objetos no "viven" aislados

ActiveRecord ofrece mecanismos para relacionar modelosAPI potente, flexible y fácil de usarLas relaciones se declaran estilo "macro"Siguiendo las convenciones, se reduce al mínimo el código

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 5 / 64

Page 6: Relaciones en Rails 3(1 1,1 n,n n)

¿Puede ser más simple?

class Artist < ActiveRecord::Basehas_many :albums

end

class Album < ActiveRecord::Basebelongs_to :artist

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 6 / 64

Page 7: Relaciones en Rails 3(1 1,1 n,n n)

¿Puede ser más simple?

album = Album.new(:title => "Born under a bad sign")albert = Artist.find_by_name("Albert King")album.artist = albertalbert.albums.each { |a| puts a.title }

gary = Artist.find_by_name("Gary Moore")gary.albums << Album.new(:title => "King of the blues")gary.albums.build(:title => "Wild frontier")

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 7 / 64

Page 8: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 8 / 64

Page 9: Relaciones en Rails 3(1 1,1 n,n n)

Especificación

class Company < ActiveRecord::Basehas_one :office

end

class Office < ActiveRecord::Basebelongs_to :company

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 9 / 64

Page 10: Relaciones en Rails 3(1 1,1 n,n n)

Tablas

companiesidname string

officesidnumber stringarea integercompany_id integer

11

has_one

belongs_to

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 10 / 64

Page 11: Relaciones en Rails 3(1 1,1 n,n n)

Referencias en las migraciones

Se puede usar el método references en la definición de tablas

create_table :offices do |t|t.string :numbert.decimal :areat.references :customer # customer_idt.timestamps

end

De todos modos, no deja de ser un entero:

create_table :offices do |t|t.string :numbert.decimal :areat.integer :customer_idt.timestamps

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 11 / 64

Page 12: Relaciones en Rails 3(1 1,1 n,n n)

Métodos de belongs_to

association(force_reload = false)

office.company

association=(associate)

office.company = Company.first

build_association(attributes = {})

office.build_company(:name => "Banot.net")

create_association(attributes = {})

office.create_company(:name => "Inventiaplus")

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 12 / 64

Page 13: Relaciones en Rails 3(1 1,1 n,n n)

Métodos de has_one

association(force_reload = false)

office.company

association=(associate)

office.company = Company.first

build_association(attributes = {})

office.build_company(:name => "Banot.net")

create_association(attributes = {})

office.create_company(:name => "Inventiaplus")

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 13 / 64

Page 14: Relaciones en Rails 3(1 1,1 n,n n)

¿Cuándo se guardan los objetos?has_one

El objeto asociado se guarda al asignarlo para actualizar su claveajenaEl objeto reemplazado (si lo hubiera), también se guardaExcepto:

I Si falla una de las validaciones, se cancela la asignaciónI Si el extremo que tiene el has_one es nuevo, se esperará (a que

este se guarde)

Para asignar sin guardar, usar el método build

Si se asigna por el extremo que tiene el belongs_to, nunca seguardan los objetos

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 14 / 64

Page 15: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 15 / 64

Page 16: Relaciones en Rails 3(1 1,1 n,n n)

Especificación

class Artist < ActiveRecord::Basehas_many :albums

end

class Album < ActiveRecord::Basebelongs_to :artist

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 16 / 64

Page 17: Relaciones en Rails 3(1 1,1 n,n n)

Tablas

artistsidname string

albumsidtitle stringartist_id integer

1n

has_many belongs_to

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 17 / 64

Page 18: Relaciones en Rails 3(1 1,1 n,n n)

Métodos de has_many (I)

collection(force_reload = false)

artist.albums

collection<<(associate)

artist.albums << Album.new

delete(object)

artist.delete(album)

collection=(objects)

albums.class # Arrayoffice.albums = albums

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 18 / 64

Page 19: Relaciones en Rails 3(1 1,1 n,n n)

Métodos de has_many (II)

collection_singular_ids / collection_singular_ids=

artist.album_ids # [1, 2]artist.album_ids = [1, 3]

clear

artist.albums.clearartist.albums # []

empty?

artist.albums.empty?

size

artist.albums.size

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 19 / 64

Page 20: Relaciones en Rails 3(1 1,1 n,n n)

Métodos de has_many (III)

find(...)

artist.albums.find_by_year(2010)artist.albums.find(:conditions => { ... })

clear

artist.albums.clearartist.albums # []

exists?

artist.albums.exists?(:year => 2010)

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 20 / 64

Page 21: Relaciones en Rails 3(1 1,1 n,n n)

Métodos de has_many (y IV)

collection.build(attributes = {})

a = artist.albums.build(:title => "Believe")a.new_record? # truea.save!

collection.create(attributes = {})

a = artist.albums.create(:title => "Asylum")a.new_record? # false

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 21 / 64

Page 22: Relaciones en Rails 3(1 1,1 n,n n)

¿Cuándo se guardan los objetos?has_many

Los objetos asociados se guardan al asignarlosExcepto:

I Si falla la validación de cualquiera de ellos, la asignación secancela

I Si el extremo que tiene en has_many es nuevo, se esperará (hastaque se guarde)

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 22 / 64

Page 23: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 23 / 64

Page 24: Relaciones en Rails 3(1 1,1 n,n n)

Especificación

class Musician < ActiveRecord::Basehas_and_belongs_to_many :bands

end

class Band < ActiveRecord::Basehas_and_belongs_to_many :musicians

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 24 / 64

Page 25: Relaciones en Rails 3(1 1,1 n,n n)

Tablas

bandsidname string

has_and_belongs_to_many

musiciansidname string

has_and_belongs_to_many

bands_musiciansband_id integermusician_id integer

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 25 / 64

Page 26: Relaciones en Rails 3(1 1,1 n,n n)

La tabla intermedia

El nombre se forma contatenando los plurales de los nombres delas clasesSe ordenan alfabéticamenteHay que indicar que no precisa clave primaria

create_table :companies_offices, :id => false do |t|t.references :companyt.references :office

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 26 / 64

Page 27: Relaciones en Rails 3(1 1,1 n,n n)

Parecidos con has_many

Simplificando, la API es la misma que en el caso de has_many

Las reglas para guardar los objetos en la base de datos tambiénson las mismasAsí que vamos a aplicar el principio DRY ;)

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 27 / 64

Page 28: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 28 / 64

Page 29: Relaciones en Rails 3(1 1,1 n,n n)

Usando la API de consultas

artist = Artist.find_by_name(’B.B. King’)artist.albums.where("year < 2000")

Simplificando, se traduce en:

SELECT * FROM "artists" LEFT OUTER JOIN "albums"ON "albums"."artist_id" = "artists"."id"WHERE (albums.year < 2000)

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 29 / 64

Page 30: Relaciones en Rails 3(1 1,1 n,n n)

Eager-loadingn + 1 consultas

albums = Album.limit(10)albums.each do |album|puts "#{album.artist.name}: #{album.title}"

end

Esto dispararía 1 consulta para recuperar los álbums. . .. . . y otra por cada album para recuperar su artista¡En total, 101 consultas!

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 30 / 64

Page 31: Relaciones en Rails 3(1 1,1 n,n n)

Eager-loadingDe n + 1 a tan sólo 2

albums = Album.includes(:artist).limit(10)

Esto dispara sólo 2 consultas:I Una para los álbumsI Y otra para todos los artistas relacionados

SELECT albums.* FROM albums LIMIT 10SELECT artists.* FROM artists WHEREWHERE (albums.artist_id IN (1, 2, 5))

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 31 / 64

Page 32: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 32 / 64

Page 33: Relaciones en Rails 3(1 1,1 n,n n)

Dependencias entre objetos

A veces la existencia de un objeto depende de otroSi por ejemplo borramos un artista, nos interesa borrar sus discos

class Artisthas_many :albums, :dependent => :destroy

end

u2 = Artist.find_by_name(’U2’)u2.destroy # Elimina a U2 y todos sus álbums

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 33 / 64

Page 34: Relaciones en Rails 3(1 1,1 n,n n)

Tipos de dependencia

destroy Llama a destroy para cada uno de los objetosasociados

delete/delete_all Borra los objetos asociados pero sin llamar adestroy

nullify Pone la clave ajena a nullrestrict No permite borrar el objeto si hay otro asociado

Se usan principalmente con has_many y has_oneDebe evitarse su uso en belongs_to por la posibilidad de dejarobjetos "huérfanos"

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 34 / 64

Page 35: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 35 / 64

Page 36: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 36 / 64

Page 37: Relaciones en Rails 3(1 1,1 n,n n)

No siempre es posible

Seguir las convenciones permite escribir menos código. . .pero no siempre es posibleAfortunadamente, ActiveRecord ofrece un buen número demodificadores

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 37 / 64

Page 38: Relaciones en Rails 3(1 1,1 n,n n)

Ignorando las convenciones

class Log < ActiveRecord::Basehas_many :log_entries

end

class LogEntry < ActiveRecord::Basebelongs_to :log

end

log.log_entries # No parece muy bonito

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 38 / 64

Page 39: Relaciones en Rails 3(1 1,1 n,n n)

Ignorando las convenciones

class Log < ActiveRecord::Basehas_many :entries, :class_name => "LogEntry"

end

class LogEntry < ActiveRecord::Basebelongs_to :log

end

log.entries # Mejor :)

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 39 / 64

Page 40: Relaciones en Rails 3(1 1,1 n,n n)

Ignorando las convenciones

class Log < ActiveRecord::Basehas_many :entries, :class_name => "LogEntry",:foreign_key => "l_id"

end

class LogEntry < ActiveRecord::Basebelongs_to :log, :foreign_key => "l_id"

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 40 / 64

Page 41: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 41 / 64

Page 42: Relaciones en Rails 3(1 1,1 n,n n)

Ordenación

Permite ordenar los objetos dentro de la relación

class Artist < ActiveRecord::Basehas_many :albums, :order => :year

end

queen = Artist.find_by_name("Queen")queen.albums.map(&:year) # [ 1973, 1974, 1974, ... ]

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 42 / 64

Page 43: Relaciones en Rails 3(1 1,1 n,n n)

Sentido de la ordenación

class Artist < ActiveRecord::Basehas_many :albums, :order => "year desc"

end

queen = Artist.find_by_name("Queen")queen.albums.map(&:year) # [ 1995, 1991, 1989, ... ]

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 43 / 64

Page 44: Relaciones en Rails 3(1 1,1 n,n n)

Ordenación compuesta

class Artist < ActiveRecord::Basehas_many :albums, :order => "year asc, title desc"

end

queen = Artist.find_by_name("Queen")queen.albums.map(&:title)# [ "Queen", "Sheer heart attack", "Queen II", ... ]

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 44 / 64

Page 45: Relaciones en Rails 3(1 1,1 n,n n)

Condiciones

Permite filtrar la relación con condiciones

class Artist < ActiveRecord::Basehas_many :albumshas_many :greatest_albums, :class_name => "Album",

:conditions => { :rate => [ 4, 5 ] }end

queen = Artist.find_by_name("Queen")queen.greatest_albums.first

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 45 / 64

Page 46: Relaciones en Rails 3(1 1,1 n,n n)

Límites

Limita la cantidad de objetos devueltos

class Artist < ActiveRecord::Basehas_many :albums, :order => :yearhas_many :latest_albums, :class_name => "Album",

:limit => 2, :order => "year desc"end

queen = Artist.find_by_name("Queen")queen.latest_albums.map(&:year) # [ 1995, 1991 ]

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 46 / 64

Page 47: Relaciones en Rails 3(1 1,1 n,n n)

EjercicioAñadiendo árbitros a Bet on Rails

1 Queremos que los usuarios de Bet on Rails sepan quién pita cadapartido

2 Añadir a Bet on Rails un modelo Referee que represente a losárbitros

3 Interesan su nombre y su fecha de nacimiento4 Implementar una gestión básica usando el "scaffold"5 Hacer que para cada partido se pueda seleccionar un árbitro

(pista: collection_select)6 ¿Cómo podría acceder a los partidos ya pitados por un árbitro?

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 47 / 64

Page 48: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 48 / 64

Page 49: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 49 / 64

Page 50: Relaciones en Rails 3(1 1,1 n,n n)

Algo con dirección

class Address < ActiveRecord::Basebelongs_to :addressable, :polymorphic => true

end

class Company < ActiveRecord::Basehas_many :addresses, :as => :addressable

end

class Person < ActiveRecord::Basehas_one :address, :as => :addressable

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 50 / 64

Page 51: Relaciones en Rails 3(1 1,1 n,n n)

¿Dónde está el truco?

Además de la columna _id, se usa una columna _type

En esa columna se guarda la clase del objeto asociado

address = Address.find_by_postal_code("35017")address.addressable_id # 1address.addressable_type # "Company"

En la migración hay que indicar que se trata de una relaciónpolimórfica

t.references :addressable, :polymorphic => true

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 51 / 64

Page 52: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 52 / 64

Page 53: Relaciones en Rails 3(1 1,1 n,n n)

¿Para qué?

Nos permite asociar dos modelos a través de un terceroUsos típicos:

1 Para añadir "lógica" a una asociación HABTM2 Como "atajo" en asociaciones has_many anidadas

Se verá más claro con dos ejemplos

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 53 / 64

Page 54: Relaciones en Rails 3(1 1,1 n,n n)

Join models

Supongamos una asociación HABTM a la que queremos añadirlógica (atributos, validaciones, etc.)

class User < ActiveRecord::Basehas_and_belongs_to_many :groups

end

class Group < ActiveRecord::Basehas_and_belongs_to_many :users

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 54 / 64

Page 55: Relaciones en Rails 3(1 1,1 n,n n)

Join models

Puede sustituirse por un modelo intermedio con dos relacionesuno a muchos

class User < ActiveRecord::Basehas_many :subscriptions

end

class Group < ActiveRecord::Basehas_many :subscriptions

end

class Subscription < ActiveRecord::Basebelongs_to :userbelongs_to :group

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 55 / 64

Page 56: Relaciones en Rails 3(1 1,1 n,n n)

Join models

create_table :subscriptions do |t|t.references :usert.references :groupt.boolean :activet.timestamps

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 56 / 64

Page 57: Relaciones en Rails 3(1 1,1 n,n n)

Join models

Así se puede llegar de un extremo al otro:

class User < ActiveRecord::Basehas_many :subscriptionshas_many :groups, :through => :subscriptions

end

class Group < ActiveRecord::Basehas_many :subscriptionshas_many :users, :through => :subscriptions

end

class Subscription < ActiveRecord::Basebelongs_to :userbelongs_to :group

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 57 / 64

Page 58: Relaciones en Rails 3(1 1,1 n,n n)

Como si fuera HABTM

Se pueden usar los métodos habituales entre los extremosSe crearán "automáticamente" nuevos objetos intermediossiempre que sea necesarioCuando se eliminen, no se llamará a "destroy"

lanzarote = User.find_by_name("Lanzarote")lanzarote.groups.empty? # truelanzarote.subscriptions.empty? # trueknights = Group.find_by_name("Knights")lanzarote.groups << knightslanzarote.subscriptions.empty? # false

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 58 / 64

Page 59: Relaciones en Rails 3(1 1,1 n,n n)

has_many anidados

class Document < ActiveRecord::Basehas_many :pages

end

class Page < ActiveRecord::Basebelongs_to :documenthas_many :paragraphs

end

class Paragraph < ActiveRecord::Basebelongs_to :page

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 59 / 64

Page 60: Relaciones en Rails 3(1 1,1 n,n n)

has_many anidados

class Document < ActiveRecord::Basehas_many :pageshas_many :paragraphs, :through => :pages

end

class Page < ActiveRecord::Basebelongs_to :documenthas_many :paragraphs

end

class Paragraph < ActiveRecord::Basebelongs_to :page

end

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 60 / 64

Page 61: Relaciones en Rails 3(1 1,1 n,n n)

Contenidos1 Asociaciones: lo básico

¿Qué son?Uno a unoUno a muchosMuchos a muchosAsociaciones y consultasDependencias

2 Asociaciones: opciones destacadasIgnorando las convencionesOrdenación y límites

3 Asociaciones avanzadasPolimórficashas_many :through

4 Herencia

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 61 / 64

Page 62: Relaciones en Rails 3(1 1,1 n,n n)

Single Table Inheritance (STI)Todos los campos —de la clase base y las derivadas— en unatablaEl tipo concreto se almacena en la columna “type”Se puede pasar la opción --parent al generador

File

-path: string-size: integer

Text

-lines: string-words: integer

Binary

-format: string

filespath stringsize stringlines integerwords integerformat stringtype string

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 62 / 64

Page 63: Relaciones en Rails 3(1 1,1 n,n n)

Ejercicio 1Modelando una plataforma de e-learning

Queremos escribir una plataforma de e-learningEn una primera versión, tenemos cursos, temas y tareas

I Cada curso tiene una serie de temas y tareas asociadasI Además, los temas y las tareas tienen asociados una serie de

documentos

Nuestros usuarios serán profesores y estudiantesUn curso puede tener varios profesores asignadosUn estudiante puede matricularse en cualquier curso

I Nos interesa saber cuándo formalizó la matrículaI Y también nos gustaría poder desactivarla en un momento dado

Implementarlo a nivel de modelos, olvidando la interfaz web

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 63 / 64

Page 64: Relaciones en Rails 3(1 1,1 n,n n)

Ejercicio 2Modelando los equipos para Bet on Rails

1 Añadir a Bet on Rails un modelo Team que representa a losequipos e implementar una gestión básica (con el "scaffold")

2 La clase Game dejará de usar cadenas para representar a losequipos y usará esa nueva clase

3 Al crear/editar mediante el navegador deben seleccionarse losequipos de los registrados en la base de datos (pista:collection_select)

4 ¿Cómo podría acceder a los partidos que un equipo ha jugado encasa?

Áncor/Imobach GS (Banot.net) Desarrollo web con Ruby on Rails 3 Octubre de 2010 64 / 64