Modificando registros a base de migraciones
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.
<p>Alguien se puede preguntar cuáles son las ventajas reales de manipular la base de datos usando Ruby en lugar de <span class="caps">SQL</span>. 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 <span class="caps">SQL</span> 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.</p>
<p>Supongamos que tenemos la tabla que vendría dada por la siguiente migración:</p>
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:
- El útil metodo
say_with_timeque nos sirve para rastrear el progreso de nuestra migración - Tras modificar cada registro hay que invocar el método
savedeActiveRecord, 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á.
