En la programación Orientada a Objetos es normal toparse con una composición entre objetos de la misma clase. Por ejemplo un persona tiene padres y tiene hijos, una clase se relaciona con sus super y sub clases, artículos cientificos tienen referencias a otros articulos científicos, etc, etc.
A la hora de realizar este mapeo en Ruby on Rails, las referencias de muchos a muchos sobre el mismo modelo presentan algunos dolores de cabeza. Estos dolores los pasé después de varias horas de googlear y leer algunos libros interesantes.
Para aquellos que tienen que realizar este problema, aca van los trucos para que puedan llevar a cabo lo más rápido posible la solución.
Diseño a resolver:
Código
class CategoryRelationship < ActiveRecord::Base belongs_to :super, :class_name =>»Category» belongs_to :sub, :class_name =>»Category» end class CreateCategoryRelationships < ActiveRecord::Migration def self.down class Category < ActiveRecord::Base has_many :generics, :foreign_key=> ‘super_id’, has_many :subs, :through => :generics has_many :specifics, :foreign_key => ‘sub_id’, end |
Explicación
Las relaciones quedan modeladas utilizando otro modelo. En este caso lo llamé CategoryRelationship y su correspondiente migration.
A tener en cuenta:
En CategoryRelationship, notar que los belongs_to hacen referencia a super y sub. En la migración las columnas se llaman igual con el «_id» al final. Como de alguna forma los nombres de las columnas de la tabla son puestas ad-hoc, utilizamos «:class_name=>»Category» » para indicar a que clase nos estamos refiriendo en los elementos de la migración.
En Category utilizamos el «has_many, :through=>» con un poco más de información. Siguiendo el ejemplo:
- has_many :generics definimos un alias que nos representa a las super categorias.
- :foreing_key => ‘super_id» con esto indicamos la clave foránea que hace referencia a nuestras super categorias. Tenemos que hacer esto porque como utilizamos alias, Rails no puede darse cuenta que super_id referencia a Categorias (recuerden que esa id son los id de categorias).
- :class_name =>’CategoryRelationship’ con esto indicamos que trabajamos sobre los elementos del mapeo de nuestra relacion CategoryRelationship.
- :dependent => ‘destroy’ indica que en el momento de borrar algun elemento de :subs, se elimina la entrada en la tabla donde está referenciado.
- has_many :subs, :through: generics Ahora si podemos hacer el has_many necesario para referenciar a nuestros subs (subcategorias). Notar que el nombre subs tiene relacion con el belongs_to de CategoryRelationship, y con el sub_id.
- Para los sup