lunes, 1 de octubre de 2012

Migraciones en Rails

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.

En el próximo post les mostraré como generar, configurar y asociar Modelos; los cuales nos permiten manipular la base de datos desde Rails de una manera bastante sencilla y práctica.