2011-10-06 14 views
24

Me gustan mucho las migraciones de estilo de Rails 3, es decir, un método change lo suficientemente inteligente como para reconocer si las migraciones se están instalando o retrotrayendo, por lo que no tengo que escribir los métodos up y down reflejándose entre sí. Pero tengo una situación en la que necesito omitir algún código cuando se retrotrae la migración (actualizando las columnas counter_cache que estoy agregando).Cómo reconocer la dirección de migración (hacia arriba o hacia abajo) con las migraciones de estilo Rails 3 (def change)?

Miré a http://guides.rubyonrails.org/migrations.html pero los ejemplos al final de la sección de 5 años padecen el mismo problema:

class AddFuzzToProduct < ActiveRecord::Migration 
    class Product < ActiveRecord::Base 
    end 
    def change 
    add_column :products, :fuzz, :string 
    Product.reset_column_information 
    Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' } 
    end 
end 

Cuando esta migración se revierte, la actualización de fuzz campo es innecesaria. ¿Hay una forma de prevenirlo?

He intentado buscar en Product.column_names pero como Rails es lo suficientemente inteligente como para realizar la migración en dirección inversa, la actualización se ejecuta antes de que se elimine la columna. Además, cuando se define el método change, los métodos up o down parecen ignorados. ¿Alguna otra idea?

+0

y Los métodos down no están en desuso para todas las versiones de rieles y son necesarios para cosas como esta. Todas las soluciones aquí provistas son malas porque no son ajenas, y tienen mal olor, y la mejor manera de resolver su problema es simplemente escribir los métodos arriba y abajo correctos – edikgat

Respuesta

20

En este caso, creo que tendrá que usar los métodos up y down como de costumbre. No se preocupe, a pesar de la adición de change en Rails 3 esos métodos no están, por lo que sé, ligados a la tabla de cortar. Continúa usándolos donde sea necesario.

Editar: Aquí hay una opción: Anular migrate.

class AddFuzzToProduct < ActiveRecord::Migration 
    class Product < ActiveRecord::Base 
    end 

    def change 
    add_column :products, :fuzz, :string 
    end 

    def migrate(direction) 
    super # Let Rails do its thing as usual... 

    if direction == :up # ...but then do something extra if we're going 'up.' 
     Product.reset_column_information 
     Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' } 
    end 
    end 
end 

¿Pensamientos?

+1

Sé que puedo definir "arriba" y "abajo" en lugar de ' change', pero preferiría usar 'change' si fuera posible, ya que reduce la duplicación. Pero supongo que tendré que usarlos si no hay otra opción :( – szeryf

+2

@szeryf Echa un vistazo a mi respuesta actualizada. Espero que esto te sea útil, y creo que debería ser bastante sólida con respecto a 'ActiveRecord: : Migration's API. –

+0

Gracias, esto se ve bien! – szeryf

0

Aquí hay una idea desagradable: @connection es el CommandRecorder cuando se va hacia abajo.

def change 
    add_column :products, :fuzz, :string 
    unless @connection.kind_of?(ActiveRecord::Migration::CommandRecorder) 
     Product.reset_column_information 
     Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' } 
    end 
end 

No lo he intentado. Obviamente estás fuera de la API de Rails por lo que podría romperse en cualquier momento.

Si sólo el método de cambio tenía una forma legítima de determinar la dirección de la migración ...

17

En los carriles 3.x también se puede hacer esto

class AddFuzzToProduct < ActiveRecord::Migration 
    class Product < ActiveRecord::Base 
    end 
    def change 
    add_column :products, :fuzz, :string 
    unless reverting? 
     # Do this only when direction is up 
     Product.reset_column_information 
     Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' } 
    end 
    end 
end 
+2

¡El enfoque más limpio de todas las sugerencias anteriores! Y también funciona para Rails 4.x. –

Cuestiones relacionadas