Desarrollar una aplicación no sólo significa implementar nuevas funciones o parchearla. A veces hay que revertir los cambios y volver a la fase anterior de un proyecto. Un problema frecuente que puede surgir mientras se trabaja en varias ramas está relacionado con el mantenimiento de la versión adecuada de una estructura de base de datos. Los programadores que utilizan rails tienen a su disposición soluciones ya preparadas. Estas soluciones soportan la implementación y el control de los cambios en la base de datos: son las migraciones. No voy a describir cómo funciona y qué posibilidades ofrece - me gustaría centrarme en el problema de mantener la versión adecuada de una estructura de base de datos mientras se cambia de rama.
La capa de base de datos de una aplicación es un ente independiente y sólo se controla mediante migraciones. Al crear nuevas migraciones, recuerde hacer reversible la transformación prevista de una estructura de base de datos. Por supuesto, en casos extremos, podemos plantear MigraciónIrreversible
en el abajo método. Esto también nos informará del hecho de que la migración no se puede revertir. Hay diferentes tipos de cambios que realizamos en la migración: crear, modificar y eliminar tablas, columnas o índices. Las operaciones de eliminación y modificación son las más sensibles a los cambios. ¿Por qué? Consideremos el siguiente escenario: Estamos trabajando con la rama maestra, que es nuestra ruta de trabajo principal. Actualmente tenemos una tabla:
class CrearArtículos < ActiveRecord::Migración
def change
crear_tabla :artículos do |t|
t.cadena :nombre
t.text :descripción
t.cadena :estado, null: false
t.timestamps null: false
end
end
end
Nuestra Artículo
tiene tales validaciones que requieren la presencia de nombre, descripción y estado atributos.
class Artículo < ActiveRecord::Base
valida :nombre, presencia: true
valida :descripción, presencia: true
valida :estado, presencia: true
end
Estamos introduciendo cambios en artículos mesa en función rama de desarrollo y eliminamos la estado columna.
class EliminarColumnaDeEstadoDeArtículos < ActiveRecord::Migration
def change
remove_column :articles, :status, :string
end
end
Ejecutamos la migración:
$ [example/feature]: bundle exec rake db:migrate
== 20150605120955 RemoveStatusColumnFromArticles: migrando ===================
-- remove_column(:articles, :status, :string)
-> 0.0717s
== 20150605120955 RemoveStatusColumnFromArticles: migrado (0.0718s) ==========
El esquema de una base de datos cambia:
diff --git a/db/schema.rb b/db/schema.rb
index 2a100a9..76438c1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,14 +11,13 @@ #
Se recomienda encarecidamente que compruebe este archivo en su sistema de control de versiones.
-ActiveRecord::Schema.define(version: 20150605120350) do
+ActiveRecord::Schema.define(versión: 20150605120955) do
createtable "articles", force: :cascade do |t|
t.cadena "nombre"
t.text "descripción"
- t.string "status", null: false t.datetime "createdat", null: false
t.datetime "updated_at", null: false
fin
end
A continuación, confirmamos los cambios en el archivo función rama. Para simular este problema cambiamos la rama actual a master. La estructura base ha sido modificada por la migración, que elimina la rama estado en la columna función rama. Intentemos utilizar el siguiente comando:
Article.create!(nombre: "Kaboom", descripción: "Lorem ipsum...", estado: "activo")
¿Qué ocurrirá después de ejecutar las código? El error: ActiveRecord::UnknownAttributeError: atributo desconocido 'status' para Article
y eso es debido a la incompatibilidad de la estructura de la versión de la base de datos. Antes de cambiar la rama a master debemos revertir la migración que borra el archivo estado de la columna Artículo mesa.
¿Qué podemos hacer para comprobar si tenemos que deshacer algunas migraciones antes de cambiar las ramas? Con el uso del sistema de control de versiones (aquí es git) podemos comprobar nuestro trabajo creando un alias útil:
~/.gitconfig
[alias]
migrations = "!f() { git diff --name-only $1..$2 db/migrate | tr -d '[A-Za-z/_.]'; }; f"
Ejecución de la git migrations master feature
obtendrá la lista de versiones de migración, que se encuentran en función ramas, y que no pueden encontrarse en maestro.
$ [ejemplo/característica]: git migrations master feature.
20150605120955
Gracias a esta información podemos revertir fácilmente los cambios realizados en la estructura de la base de datos antes de pasar a maestra.
$ [example/feature]: bundle exec rake db:migrate:down VERSION=20150605120955
== 20150605120955 RemoveStatusColumnFromArticles: revirtiendo ===================
-- add_column(:articles, :status, :string)
-> 0.0009s
== 20150605120955 RemoveStatusColumnFromArticles: revertido (0.0045s) ==========
Una cosa más que debemos hacer después de hacer retroceder la migración es restaurar el estado de un esquema de base de datos.
$ [ejemplo/característica]: git status
En la rama característica
Cambios no preparados para confirmar:
(usa "git add ..." para actualizar lo que se confirmará)
(usa "git checkout -- ..." para descartar los cambios en el directorio de trabajo)
modificado: db/schema.rb
no se han añadido cambios al commit (usa "git add" y/o "git commit -a")
$ [ejemplo/característica]: git checkout db/esquema.rb
$ [ejemplo/característica]: git status
En la rama característica
nada que confirmar, directorio de trabajo limpio
Ahora podemos cambiar fácilmente al maestro rama.
El ejemplo dado no es un problema complicado de resolver, pero debería ayudarle a darse cuenta de lo importante que es mantener la estructura de una base de datos durante el cambio en el contexto de trabajo.