Las series de cursos Ruby on Rails en CodeHero buscan otorgarte los conocimientos necesarios, para que puedas desarrollar tus propias aplicaciones Web. En el capítulo anterior estudiamos conceptos básicos de ActiveRecord, pero aún nos quedan conceptos de este tema.
En este nuevo capítulo estudiaremos las asociaciones con ActiveRecord, tema que se debe conocer bien para luego proseguir con la parte dos de ActiveRecord.
Asociaciones
¿Por qué necesitamos las asociaciones entre los modelos? Porque hacen operaciones comunes más simple y más fácil en el código. Por ejemplo, si tenemos una aplicación Rails sencilla que incluye un modelo para los usuarios y un modelo para las direcciones y cada usuario puede tener varias direcciones. Esto sin las asociaciones de Rails tendríamos que hacer consultas y validaciones por separado para cada uno de los objetos, esto aunque no esta mal, es ineficiente. Veamos un poco como es la sintaxis para estos ejemplo y así posteriormente mostrar los tipos de asociaciones de tablas que podemos hacer para simplificarnos la vida:
class Usuario < ActiveRecord::Base has_many :direccions, dependent: :destroy end class Direccion < ActiveRecord::Base belongs_to :Usuario end
Con esta sintaxis le estamos diciendo a Rails que un usuario puede tener muchas direcciones (“has_many”) y una dirección solo puede tener un Usuario (“belongs_to”), a su vez al agregar la dependencia de (“destroy”) le estaríamos agregando una relación de cascada al eliminar usuarios, es decir, si borramos un usuario eliminaríamos todas sus direcciones de inmediato.
Tipos de asociaciones
En Rails, tenemos seis tipos de asociaciones para enlazar modelos ActiveRecord, que son los siguientes:
belongs_to
Esta asociación establece una relación de uno a uno con otro modelo, de forma que cada instancia del modelo “pertenece” a una instancia del otro modelo. Por ejemplo, si la aplicación tiene Usuarios y Direcciones y cada dirección le pertenece a un usuario. Esto se definiría así:
class Direccion < ActiveRecord::Base belongs_to :usuario end
has_one
Esta asociación también establece un uno a uno con otro modelo, pero con algunas diferencias con respecto a tipo de asociación anterior. Esta asociación indica que cada instancia de un modelo contiene o posee una instancia de otro modelo. Por ejemplo, si cada Usuario tiene una Dirección, se declararía de la siguiente manera:
class Usuario < ActiveRecord::Base has_one :direccion end
Llegado a este punto quizás te preguntaras, si al crear una relación uno a uno que tipo de asociación debemos elegir para cada uno de los componentes.
La diferencia básicamente es que has_one nos dice que le pertenece algún objeto y el belongs_to que pertenece a algo, tal y como vimos en el ejemplo anterior un usuario posee una dirección y la dirección le pertenece a un usuario.
has_many
Esta asociación indica el enlace de uno a muchos con otro modelo. Esta asociación pueden encontrarse por lo general en el opuesto de un “belongs_to” e indica que cada objeto de un modelo puede tener muchos objetos relacionados a el (o ninguno). Por ejemplo Un usuario puede tener múltiples direcciones eso se declararía de la siguiente manera:
class Usuario < ActiveRecord::Base has_many :direccions end
has_many :through
Esta asociación se utiliza a menudo para establecer conexiones de muchos a muchos con otro modelo. Esta asociación al igual que “has_many” nos indica que cada objeto de un modelo puede tener muchos objetos asociados, la única diferencia es que para lograr un muchos a mucho debemos agregar un tercer modelo que relacione los anteriores. Entendamos mejor esto con un ejemplo: Si un cliente lo visitan a su dirección muchos vendedores y un Vendedor visita muchos clientes, esta afirmación se declararía de la siguiente manera:
class Usuario < ActiveRecord::Base has_many :direccions has_many :vendedors, through: :direccions end class Direccion < ActiveRecord::Base belongs_to :vendedor belongs_to :usuario end class Vendedor < ActiveRecord::Base has_many :direccions has_many :usuarios, through: :direccions end
Con este ejemplo al invocar un vendedor podemos tener todas las direcciones y los clientes a visitar rápidamente.
has_one :through
Esta asociación se utiliza para realizar enlaces uno a uno y nos es útil para establecer algunos atajos a través de otra entidad, por ejemplo si un usuario tiene una dirección y a su vez esta dirección tienen un numero de teléfono, quizás sea apropiado establecer un atajo para obtener todos los teléfonos de un usuario, esta afirmación se pudiera establecer de la siguiente manera:
class Usuario < ActiveRecord::Base has_one :direccion has_one :telefono, through: :direccion end class Direccion < ActiveRecord::Base belongs_to :usuario has_one :telefono end class Telefono < ActiveRecord::Base belongs_to :direccion end
has_and_belongs_to_many
Por último esta asociación crea una relación de muchos a muchos con otro modelo, sin necesidad de declarar un modelo para la entidad débil que enlaza estas dos entidades en la base de datos. Por ejemplo, si tenemos una aplicación que donde un vendedor puede atender a múltiples clientes y a su vez un cliente puede ser atendido por múltiplos vendedores (sin que nos importe la entidad que los relacionaría en la base de datos), entonces podemos diseñar esta estructura de la siguiente forma:
class Vendedor < ActiveRecord::Base has_and_belongs_to_many :clientes end class Cliente < ActiveRecord::Base has_and_belongs_to_many :vendedors end
Al igual que con el has_one y belongs_to llegado a este punto podríamos preguntarnos: ¿Qué debemos utilizar para establecer una relación de muchos a muchos: has_and_belongs_to_many o has_many :through?
La respuesta la tenemos estudiando la necesidad del problema, si en nuestro planteamiento vemos necesario trabajar con el modelo que relaciona las dos entidades principales utilizamos has_many :through, o por el contrario, no tenemos pensado hacer ningún uso de esta entidad relación a nivel de código, nos conviene más utilizar has_and_belongs_to_many
Polimorfismo en las asociaciones
Esta es una forma de asociación un poco mas avanzada que nos permite relacionar un modelo y éste pueda pertenecer a más de un modelo en una sola asociación. El típico ejemplo para atender mejor esto, es el del objeto multimedia, por lo general utilizamos este modelo para asociarlo a otros objetos como usuarios o productos y así estos últimos puedan manejar sus imágenes independientes. Veamos como seria esto en código:
class Multimedia < ActiveRecord::Base belongs_to :multimediable, polymorphic: true end class Usuario < ActiveRecord::Base has_many :multimedias, as: :multimediable end class Producto < ActiveRecord::Base has_many :multimedias, as: :multimediable end
Conclusión
En esta lección conocimos la estructura para establecer relaciones o asociaciones entre modelos, conceptos bastante útiles que nos permitirán crear y manipular bases de datos complejas sin necesidad de interactuar con código SQL.
Una vez más te recomiendo echarle un vistazo a la serie completa de Ruby desde cero, agradeciendo de antemano todas sus dudas y comentarios en la sección de comentarios.
¡Hasta el próximo capítulo!