Migración de Modelos de Active Record a Mongoid

Clase 5 de 34Curso Intermedio de Ruby on Rails

Contenido del curso

Pruebas

Resumen

Cuando decides cambiar de Postgres a MongoDB en un proyecto Rails, la migración de modelos es uno de los pasos más críticos. Aquí se aborda cómo reemplazar la herencia de ActiveRecord por la composición de módulos de MongoID, transformando tres modelos independientes: category, note y participant.

¿Por qué eliminar application record al migrar a MongoID?

El archivo application_record.rb cumple un rol fundamental en ActiveRecord: actúa como una clase abstracta que permite definir comportamientos dinámicos y single table inheritance (herencia entre tablas). Sin embargo, MongoID maneja estos comportamientos de forma natural, por lo que este archivo deja de ser necesario [01:00].

La diferencia clave está en el enfoque arquitectónico. ActiveRecord usa herencia para conectar los modelos con la base de datos, mientras que MongoID usa composición de módulos [01:22]. Esto significa que tus modelos pueden heredar de cualquier otra clase y aún funcionar como modelos de MongoID, algo imposible con ActiveRecord en sistemas de herencia simple.

Una vez eliminado application_record.rb, es necesario remover todas las dependencias de herencia en los modelos que lo utilizaban.

¿Cómo se define un modelo de MongoID con sus campos?

Para convertir un modelo, se reemplaza la herencia por la inclusión del módulo Mongoid::Document [02:02]. Este módulo establece que la clase es un modelo de MongoID. Además, se incluye Mongoid::Timestamps para generar automáticamente los campos created_at y updated_at [02:16].

¿Cómo se migra el modelo category?

A diferencia de ActiveRecord, que define su esquema en archivos de migración separados, MongoID define la estructura de datos directamente en el modelo [02:30]. Para category, los campos se declaran así:

ruby class Category include Mongoid::Document include Mongoid::Timestamps

field :name, type: String field :description, type: String

has_many :tasks validates :name, presence: true end

  • El campo id lo maneja MongoID internamente.
  • No existe un tipo text en MongoID; String sirve tanto para cadenas cortas como largas [03:24].
  • Las validaciones y asociaciones como has_many y validates son compatibles porque MongoID utiliza internamente ActiveModel como referencia [03:44].

¿Qué cambia en el modelo note con belongs_to?

El modelo note tiene asociaciones de tipo belongs_to hacia user y task [04:22]. En MongoID, no es necesario declarar explícitamente las llaves foráneas como user_id o task_id, ya que belongs_to las crea automáticamente [04:34].

ruby class Note include Mongoid::Document include Mongoid::Timestamps

field :body, type: String

belongs_to :user belongs_to :task end

Solo fue necesario agregar el campo body de forma explícita.

¿Cómo reemplazar el método enum de ActiveRecord en MongoID?

El modelo participant presenta un desafío particular: utiliza el método enum de ActiveRecord para definir roles [05:14]. Este método genera accesores y scopes de forma automática, pero en MongoDB no es tan natural [05:34].

La solución consiste en crear una constante con los pares clave-valor y un método público que la exponga:

ruby class Participant include Mongoid::Document include Mongoid::Timestamps

ROLES = { owner: 0, editor: 1, viewer: 2 }.freeze

field :role, type: Integer

belongs_to :user belongs_to :task

def self.roles ROLES end end

  • Se declara el campo role con tipo Integer [06:22].
  • El método de clase roles permite acceder a la constante sin alterar la implementación del resto del proyecto [06:08].
  • Aunque existe una gema llamada mongoid-enum, en este caso se optó por código puro para no saturar el proyecto con dependencias innecesarias [05:50].

El orden recomendado para organizar la definición de un modelo es: módulos, campos, relaciones y validaciones [04:00]. Esta estructura facilita la lectura y el mantenimiento del código.

¿Has migrado proyectos de ActiveRecord a MongoID? Comparte tu experiencia y los retos que encontraste en el proceso.