En otras ocasiones hemos hablado de las migraciones de Rails, una característica que nos permite modificar el esquema de la base de datos usando Ruby.

Alguien se puede preguntar cuáles son las ventajas reales de manipular la base de datos usando Ruby en lugar de SQL. La primera de ellas es que sólo tendremos que lidiar con las peculiaridades de Ruby, en vez de tener que andar consultando las referencias del dialecto de SQL que haya tenido a bien implementar el fabricante de nuestro gestor de bases de datos. La segunda es que, además de modificar el esquema de la base de datos añadiendo tablas, columnas, etc. con las migraciones podemos modificar los datos ya existentes en nuestras tablas.

Supongamos que tenemos la tabla que vendría dada por la siguiente migración:

1
2
3
4
5
6
7
8
9
10
11
class Inicial < ActiveRecord::Migration
  def self.up
    create_table :entradas do |t|
         t.column :voz, :string
         t.column :inicial, :char
         t.column :texto, :text 
    end
  end

  def self.down
  end

Se trata de crear una tabla que nos sirva de diccionario, donde cada voz o palabra tiene un texto asociado pero además una inicial que será el campo que usaremos a la hora de buscar. La inicial, por definición, es la primera letra de la voz.

Pues bien, este esquema para nuestro diccionario tiene un problema: en un diccionario en castellano deberíamos poder buscar por las letras ll y ch. Al haber usado sólo un carácter para la columna inicial no podemos distinguir entre las palabras que empiezan por l y por ll.

Migraciones al rescate: no sólo vamos a cambiar la columna de inicial la base de datos, que pasará a ser una cadena en lugar de un sólo carácter, sino que además rellenaremos esa columan correctamente, comprobando si la voz empieza por ch, por ll o por cualquier otra letra:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class LetrasPorCadenas < ActiveRecord::Migration
  
  def self.dame_inicial str
    pat = /^(ch|ll|[^ ])/
    refs = pat.match str
    refs[0]
  end
  
  def self.up
    remove_column :entradas, :inicial
    add_column :entradas, :inicial, :string
    
    Entrada.reset_column_information
    say_with_time "Genero las iniciales" do
      Entrada.find(:all).each do |e| 
        e.inicial = dame_inicial(e.voz)
        e.save
      end
    end
  end

end

Son a destacar:

  1. El útil metodo say_with_time que nos sirve para rastrear el progreso de nuestra migración
  2. Tras modificar cada registro hay que invocar el método save de ActiveRecord , o de lo contrario la tupla no se modificará—no he visto mención a este detalle en ninguno de los tutoriales de migraciones que he encontrado por ahí.

No intentes casar expresiones regulares usando tu dialecto favorito de SQL. Tu salud mental te lo agradecerá.

4 Responses to “Modificando registros a base de migraciones”

  1. Efrén Says:
    Tienes razón, en ninguno de los tutoriales menciona lo del save y es importante. Yo estaba generando un hash para guardar en una columna y me dió mucho trabajo darme cuenta que faltaba el save.
  2. Esteban Manchado Says:
    No entiendo qué tiene que ver el save y las migraciones. En este caso, uno está cogiendo objetos normales ActiveRecord y los está modificando. Por tanto, habrá que llamar al save cada vez, ¿no? :-?? Quiero decir, que no es nada específico de migraciones, no veo por qué lo deberían nombrar ahí...
  3. Epaminondas Pantulis Says:
    Esteban: totalmente de acuerdo, es el comportamiento que debería tener. Sin embargo, si te miras "la documentación de las migraciones":http://api.rubyonrails.com/classes/ActiveRecord/Migration.html, en el apartado "Using a model after changing its table", fíjate que se calcula el campo @salary@ de cada registro de la tabla @Person@... ¡pero no se hace un @save@! Vamos, que como ejemplo de migración que modifica datos creo que ese fragmento de código no sólo no ayuda sino que despista un poco.
  4. Esteban Manchado Says:
    Epaminondas: ¡Aah, la leche! No lo había visto. Lo único que había visto de la documentación de migraciones era la parte de modificar la estructura de las tablas, y no me había fijado en ese ejemplo. Veo que a veces es mejor _no_ leer la documentación, y actuar por intuición :-P

Leave a Reply