Trabajar con Rails implica utilizar el patrón de desarrollo MVC (Modelo-Vista-Controlador), en el cual mantenemos separados entre sí los datos, la lógica y las interfaces gráficas; para así tener una mejor organización del código y facilitar su mantenimiento y evolución.
Antes de comenzar
Lo primero que debemos hacer antes de escribir la primera línea de código es definir y diseñar los Modelos que representen la información que será manipulada por nuestra aplicación. Pienso que ésta es la parte más importante en la etapa de desarrollo de un sistema, por lo que recomiendo dedicarle todo el tiempo, atención y cuidado posible.
Para diseñar los modelos debemos tener completamente definidas las características y requerimientos del sistema que desarrollaremos. A partir de esta información, podemos crear diagramas y otra documentación que posteriormente nos será de ayuda para el modelado de datos.
Modelos y Migraciones
Los Modelos nos permiten manipular desde Rails los datos que se encuentran almacenados en nuestra base de datos relacional (PostgreSQL, MySQL, SQLite, etc); por tanto su estructura y definición dependerán de la estructura y definición de nuestra Base de Datos.
Las Migraciones nos permiten crear y modificar nuestra base de datos de manera organizada y estructurada; ademá de que reduce casi completamente el uso de SQL. También nos permiten manejar versiones del estado de la base de datos (es como utilizar un CVS exclusivo para la base de datos).
Como era de esperarse, ambos son definidos en Ruby, y una característica super importante es que son independientes de todo manejador de base de datos, por lo que no tenemos que preocuparnos por particularidades de cada uno.
Este post se lo dedicaré exclusivamente a las Migraciones.
Crear Migraciones
Para crear una migración, usamos el siguiente comando:
$ rails generate migration NombreDeLaMigracioón
Lo cual nos generará un archivo como este:
class NombreDeLaMigración < ActiveRecord::Migration def change end end
La ubicación predeterminada del archivo es db/migrations/, y el nombre del archivo tendrá el formato YYYYMMDDHHMMSS_nombre_de_la_migracion.rb:
db/migrations/YYYYMMDDHHMMSS_nombre_de_la_migracion.rb
El timestamp YYYYMMDDHHMMSS es asignado automáticamente por Rails
Escribir Migraciones
Ya que hemos creado nuestra migración, procedemos a definirla para construir nuestra base de datos. ActiveRecord::Migration nos ofrece un conjunto de métodos que podemos utilizar para crear y modificar tablas y columnas. Como ejemplo crearemos los modelos Producto y Categoría:
# db/migrations/20121001220247_crear_productos.rb class CrearProductos < ActiveRecord::Migration def up create_table :productos do |t| t.string :nombre t.string :descripcion t.float :precio t.timestamps end end def down drop_table :productos end end # db/migrations/20121001220434_crear_categorias.rb class CrearCategorias < ActiveRecord::Migration def up create_table :categorias do |t| t.string :nombre t.timestamps end end def down drop_table :categorias end end
Ahora analicemos detenidamente:
- En el método up definimos las adiciones o modificaciones que deseamos aplicarle a la base de datos.
- En el método down definimos las acciones opuestas a las del método up. De esta manera, Rails sabrá qué hacer cuando queramos revertir alguna migración.
- Los tipos de datos soportados por Rails son: binary, boolean, date, datetime, decimal, float, integer, primary_key, string, text, time y timestamp.
- Sin necesidad de especificarlo, Rails por defecto genera un campo id (primary_key) para cada tabla.
- timestamps es un helper que genera los campos created_at (fecha y hora de creación) y updated_at (fecha y hora de la última actualización). Estos campos (al igual que el campo id) son gestionados por Rails.
- En Rails 2.1 se introdujo el método change, en el cual indicamos únicamente las instrucciones de adición o modificación (similar a las indicadas en el método up); sin necesidad de especificar las instrucciones de reversión (del método down). De esta manera, será Rails quien se encargue de determinar las acciones de reversión adecuadas. Si reescribimos la anterior definición haciendo uso del método change, obtenemos:
# db/migrations/20121001220247_crear_productos.rb class CrearProductos < ActiveRecord::Migration def change create_table :productos do |t| t.string :nombre t.string :descripcion t.float :precio t.timestamps end end end # db/migrations/20121001220434_crear_categorias.rb class CrearCategorias < ActiveRecord::Migration def change create_table :categorias do |t| t.string :nombre t.timestamps end end end
Las definiciones soportadas por el método change son:
- add_column: añadir columna
- add_index: añadir índice
- add_timestamps: añadir timestamps
- create_table: crear tabla
- remove_timestamps: eliminar timestamps
- rename_columns: renombrar columna
- rename_index: renombrar índice
- rename_table: renombrar tabla
Más Opciones
También podemos definir propiedades específicas de las columnas:
# valores por defecto t.decimal :price, default: 0.0 # presencia t.string :email, null: false # índice de unicidad # -- después del método up o change add_index :users, :email, unique: true
Ejecutar Migraciones
Para ejecutar las migraciones hacemos uso de Rake, el cual generará o actualizará el archivo db/schema.rb según las definiciones indicadas en las migraciones. Este archivo representa el estado físico de la base de datos.
// ejecutar todas las migraciones que no hayan sido ejecutadas aún $ rake db:migrate
También podemos ejecutar una migración en específico indicando su timestamp:
$ rake db:migrate VERSION=19700101000000
Revertir Migraciones
Podemos revertir migraciones de varias maneras:
// revertir la última migración $ rake db:rollback // revertir las últimas 4 migraciones $ rake db:rollback STEP=4 // resetear la base de datos (borrar, crear y migrar) $ rake db:reset
Pueden conseguir más información en Ruby on Rails Guides: Migrations.