[HowTo] Cómo simular una relación "has_many :through" en Mongoid #Rails


Esta es una duda que me carcomía por dentro desde hace tiempo, ya que como muchos saben, estas relaciones has_many :through son especialmente útiles en apps Rails que llevan una lógica sofisticada y/o complicada... Usando Rails con una base de datos relacional todo es tan fácil como tener un modelo de join que una por medio de foreign keys a los modelos en cuestión y demás, pero cuando usamos MongoDB no tenemos acceso a las joins porque Mongo (por rendimiento y tipo de paradigma) no las soporta directamente. Mientras que en varios casos podemos simplemente "darle vueltas" al asunto con otro tipo de relación/relaciones (que pueden resultar en queries raras y de poco rendimiento) a veces nos vemos obligados a usar este tipo de relación y si como yo usas MongoDB a través de Mongoid en Rails en lugar de una DB relacional, esto te puede causar una jaqueca jajajaja.

Bien, pues sucede que después de mucho leer y experimentar, di con un enfoque que me gustó bastante, les explicaré poco a poco: Supongamos que tenemos una situación donde 1 niño puede tener muchos premios a través de estrellitas (como cuando yo solía ir al kínder, el niño con más estrellitas se llevaba el peluche de la clase a su casa el fin de semana jajaja XD); Para poder modelar esto, necesitamos 3 modelos obviamente: Kid, Star y Prize. Abajo, les mostraré cómo deberían quedar los modelos (con comentarios) para lograr que la asociación funcione como queremos:

Kid Model:

Star Model:

Prize Model:

Teniendo la data modelada de esta manera, ya tendremos acceso a todas las funciones e interacciones que una asociación has_many :through nos ofrece cuando usamos una base de datos relacional en Rails pero en este caso usando MongoDB a través de Mongoid en nuestra app... Sin embargo, ¡no hemos acabado!

Faltan algunas configuraciones que debemos hacer por comodidad; Por ejemplo, sería bueno hacer un override del atributo ID automático para los objetos cuyos ID's ocupamos pasar a través del modelo de conexión (Star en este caso) de manera que no tengamos que escribir el ID completo que nos da Mongoid, sino uno más fácil de recordar. Para esto, añadimos esta linea:

field :_id, type: String, default: ->{ name.to_s.parameterize }

A los modelos Kid y Prize antes de los campos normales... Aquí lo que estamos haciendo es convertir el atributo "name" de ambos modelos en el ID predeterminado, de manera que cuando creemos un objeto Star, (como tenemos que pasarle los ID's de los objetos a interconectar) nos sea más fácil en caso de que tengamos que hacerlo a mano.

Y pues básicamente esto es todo... Así es como logras la simulación de la has_many :through en Mongoid. Cómo uses este "modelaje" depende mucho de ti y tu uso, en este caso el ejemplo es muy poco "práctico" ya que nunca harás una app para un kinder (y lo que tenemos aquí no tiene mucha "forma" que digamos aunque fueras a hacer una XD), pero la lógica pues es la misma en muchos casos. De ti depende cómo crearás tus views para aprovechar esta info o cómo pasarás los parámetros y demás, así mismo cómo manejarás la data (usando callbacks, validaciones, etc).

Espero que este tuto les haya servido, nos vemos!

P.D. Recuerden usar los métodos adecuados para Mongoid al hacer sus queries