Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Ingeniera de Sistemas de
Informacin!
Grado en Ingeniera en Tecnologas de
Telecomunicacin!
GSyC!
GSyC!
2!
Asociaciones y Claves
forneas
(ELLS 7.3)!
Asociaciones en Rails!
Sirven para modelar las relaciones lgicas entre dos
tipos de entidades en una arquitectura SW!
ActiveRecord::Associations proporciona un conjunto de
mtodos de clase que generan mtodos proxy!
Los mtodos proxy generados ligan instancias de
modelos que estn relacionadas entre s a travs de
claves forneas de sus respectivas tablas en la BD!
Hacen ms natural y fcil la creacin, modificacin y
eliminacin de modelos relacionados/asociados a travs
de claves forneas en las tablas de la BD sin tener que
usar operadores relacionales!
GSyC!
4!
5!
Diagrama Entidad/Relacin!
name
provider
uid
potatoes
comments
id
id
Moviegoer
rating
Reviews
release_date
title description
Movie
6!
GSyC!
7!
Modelo Relacional!
En el modelo relacional las relaciones entre tablas se expresan con claves forneas
(FK, foreign keys)!
Una columna de una tabla A que contiene la foreign key de una tabla B contiene
claves primarias de filas(objetos) de la tabla B!
Sirve para relacionar cada fila(objeto) de la tabla A con una fila(objeto) de la tabla B!
Recuerda que en Rails las migraciones crean tablas cuya columna de clave primaria
se llama id!
reviews
movies
id!
title!
rating!
13! Inception!
PG-13!
PG!
id!
movie_id!
moviegoer_id!
potatoes!
21!
41!
1!
5!
22!
13!
2!
3!
23!
13!
1!
4!
moviegoers
id!
name!
1!
alice!
2!
bob!
3!
carol!
8!
Operaciones relacionales!
9!
tabla movies'
Operaciones relacionales!
tabla 'reviews'
id
title
id
potatoes
movie_id
13
Inception
21
41
41
Star Wars
22
13
43
Its complicated
23
13
movies.title
reviews.id
reviews.potatoes reviews.movie_id
13
Inception
21
41
13
Inception
22
13
13
Inception
23
13
41
Star Wars
21
41
41
Star Wars
22
13
41
Star Wars
23
13
43
Its complicated
21
41
43
Its complicated
22
13
43
Its complicated
23
13
movies.title
reviews.id
reviews.potatoes reviews.movie_id
13
Inception
23
13
41
Star Wars
21
41
movies.title
Inception
reviews.id
23
reviews.potatoes reviews.movie_id
4
GSyC!
13
10!
Operaciones relacionales!
Producto
cartesiano!
11!
Mapping Object=>Relacional!
En lugar de tener que escribir consultas en SQL y ser conscientes
de la existencia de las tablas y las FK, nos gustara manejar objetos
Ruby:!
inception = Movie.find_by_title('Inception')
alice=Moviegoer.find(alice_id)
bob=Moviegoer.find(bob_id)
http://pastebin.com/NcezVx7R
GSyC!
12!
Mdulo
ActiveRecord::Associations!
has_many, has_one, belongs_to son llamadas a mtodos de
ActiveRecord::Associations!
Estos mtodos de clase utilizan metaprogramacin para generar
mtodos proxy nuevos en el modelo que permiten atravesar las
asociaciones, construyendo las queries adecuadas para la BD de
manera transparente al programador!
Forman parte del mapping Object=>Relational que permite que el
programador trabaje en trminos OO y no en trminos del modelo
relacional!
Asocian modelos, permitiendo manipular las relaciones del modelo
relacional implementadas en las tablas con PK, FK, de un modo ms
Ruby: objetos que contienen objetos: review.moviegoer,
review.movie, moviegoer.reviews, movie.reviews
Tras llamar a has_many, has_one, belongs_to, casi no hay que pensar
en trminos de PK, FK, de joins, de relaciones/tablas!
OJO!: el programador tiene que aadir las FK en la migracin!
GSyC!
13!
La idea!
Gracias a que la tabla reviews tiene un
14!
http://pastebin.com/huJagzRZ
15!
http://pastebin.com/GBTCH47f
end
class Moviegoer < ActiveRecord::Base
has_many :reviews
end
16!
Mtodos proxy de la
Association!
Ahora ya podemos escribir cdigo ms OO para
manipular la BD relacional:
@movie.reviews # Enumerable
Y en el otro sentido:
@review.movie
GSyC!
17!
18!
Cmo funciona?!
Los modelos que participan en una asociacin tienen que
tener un atributo con la FK del objeto al que pertenecen!
e.g., movie_id in reviews table!
GSyC!
19!
GSyC!
20!
Integridad referencial!
Qu ocurre si borramos una pelcula de la que existen crticas?!
El campo FK movie_id de sus crticas en la tabla reviews referencia una
PK que ya no existe. !
Esta es una razn por la que las PK nunca se reciclan en una tabla: sera
desastroso si una nueva pelcula adquiriese la misma clave primaria que la
antigua pelcula!
21!
GSyC!
22!
Asociaciones mltiples
muchos-a-muchos / many-to-many
con has_many X :through Y
y has_and_belongs_to_many X
Muchos a muchos!
GSyC!
24!
Asociaciones muchos-a-muchos!
Escenario: Los moviegoers critican movies!
un moviegoer puede tener
muchas crticas!
pero una movie tambin puede tener muchas
crticas!
25!
Asociaciones muchos-a-muchos!
Cmo obtener todas las movies criticadas
por un moviegoer? !
Podemos hacerlo usando las asociaciones
actuales entre Movie y Moviegoer:!
m.reviews.map { |r|
r.moviegoer.name }
GSyC!
26!
has_many :through
moviegoer: has_many
:reviews
has_many :movies, :through => :reviews
movie: has_many
:reviews
reviews: belongs_to
:moviegoer
belongs_to :movie
GSyC!
27!
Through!
Ahora podemos escribir esto:!
@user.movies # movies rated by user
@movie.moviegoers # users who rated this
movie
GSyC!
28!
GSyC!
29!
Through: OJO!
Nunca deberamos hacer esto:!
alice = Moviegoer.find_by_name(Alice)
alice.movies << Movie.find_by_name
(Inception)
Dado que movies es un has_many through reviews, creara
una review con potatoes y comments a nil (qu si no?)
para ligar la moviegoer alicia con la pelcula!
Podramos evitarlo aadiendo validates_presence_of :comments
y validates_presence_of :potatoes al modelo Review
GSyC!
30!
Has_and_belongs_to_many!
En una relacin many-to-many en la que no hay atributos
descriptivos en la relacin, para qu queremos el modelo
Review?!
Ejemplo: moviegoers likes movies!
Queremos poder saber las pelculas que le gustan a un moviegoer, y
todos los moviegoers a los que les gusta una pelcula!
@a_moviegoer.movies!
@a_movie.moviegoers!
31!
Has_and_belongs_to_many!
El nombre de la tabla ha de ser la concatenacin de los nombres de las
tablas de las entidades, en orden lexicogrfico y separados por un
underscore:!
Movies y moviegoers => moviegoers_movies!
En la migracin se incluyen los campos de las foreign keys, y se requiere
explcitamente que no se aada campo de clave para esta tabla:!
class CreateLikesJoinTable < ActiveRecord::Migration
def change
create_table :moviegoers_movies, :id => false do |t|
t.references :moviegoer
t.references :movie
end
end
end
GSyC!
32!
GSyC!
34!
36!
37!
/movies/:movie_id/reviews(.:format)
/movies/:movie_id/reviews(.:format)
/movies/:movie_id/reviews/new(.:format)
/movies/:movie_id/reviews/:id/edit(.:format)
/movies/:movie_id/reviews/:id(.:format)
/movies/:movie_id/reviews/:id(.:format)
/movies/:movie_id/reviews/:id(.:format)
reviews#index
reviews#create
reviews#new
reviews#edit
reviews#show
reviews#update
reviews#destroy
GSyC!
38!
reviews_controller.rb
def create
@movie = Movie.find(params[:movie_id])
# asigna @movie.id a @review.movie_id
@review = @movie.reviews.build(params[:review])
# Recuerda: @current_user tiene el valor asignado en el filtro de
#
set_current_user de ApplicationController
# asigna @current_user.id a @review.moviegoer_id
@current_user.reviews << @review
if @review.save
flash[:notice] = 'Review successfully created.'
redirect_to(movie_review_path(@movie.id, @review.id))
else
render :action => 'new'
end
end
http://pastebin.com/ngViCREC
GSyC!
39!
views/reviews/new.html.haml
= form_tag movie_reviews_path(@movie) do
= label :review, :potatoes, 'How many potatoes?'
= select :review, :potatoes, [1,2,3,4,5]
= label :review, :comments, 'Comments'
= text_area :review, :comments
= submit_tag 'Create Review'
GSyC!
40!
Referencias!!
A Guide to Active Record Associations!
http://guides.rubyonrails.org/association_basics.html!