rails ruby-on-rails ruby-on-rails-4 rails-activerecord rails-migrations

ruby-on-rails - rollback migration rails



La migración reversible para change_column_default no tiene ningún valor predeterminado en Rails (6)

Usando from y to se added en Rails 5+

La guía vinculada a la pregunta es para Edge Rails, no para una versión de lanzamiento de Rails.

La sintaxis reversible para change_column_default es el resultado de la solicitud de extracción added . La solicitud de extracción también actualizó las guías Rails para Edge Rails.

Desde activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb :

- def change_column_default(table_name, column_name, default) + # Passing a hash containing +:from+ and +:to+ will make this change + # reversible in migration: + # + # change_column_default(:posts, :state, from: nil, to: "draft") + # + def change_column_default(table_name, column_name, default_or_changes)

La solicitud de extracción se realizó el 27 de junio de 2015, que es más reciente que cualquier versión de Rails lanzada a partir del 1 de agosto de 2015.

La documentación para la migración de Rails 4.2.3 refleja el hecho de que la sintaxis reversible aún no está disponible:

change_column_default :products, :approved, false

Las guías de Rails para migraciones de registros activos dicen que puedes hacer

change_column_default :products, :approved, from: true, to: false

Tengo un método de change en Rails que es similar al siguiente:

change_column_default :people, :height, from: nil, to: 0

con la intención de pasar de no tener valores predeterminados a tener un valor predeterminado de cero.

Sin embargo, cuando intento retroceder, me sale

ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration

Teniendo en cuenta que le doy un nombre a Rails, ¿por qué no lo acepta?

Estoy usando Rails 4.2.0.


A partir de octubre de 2016, esta función (que usa to: y from: para que change_column_default sea ​​reversible) ahora está disponible en la rama 5.x. Desafortunadamente no está disponible 4.2.xo inferior. :(

Verificación: git tag --contains f9c841927ac3d1daea2a9cebf08b18e844e5eec5 : git tag --contains f9c841927ac3d1daea2a9cebf08b18e844e5eec5 en el proyecto de rieles.


Cuando intente degradar el tipo de datos, de value (0) a nil en este caso, Rails se quejará de este error. Porque podría perder datos.

Otro ejemplo sería ir desde string -> integer .

Este es un muy buen articulo explicando lo mismo.

ACTUALIZAR

Parece que sus llamadas de migración inversa change_column_default en change_column_default (activerecord-4.2.0/lib/active_record/migration/command_recorder.rb#76) comprueban si establece nil como el valor predeterminado.

Actualización2

Resulta que, si usa el change en las migraciones, esas tienen que ser capaces de ser reversibles.

pero change_column no es reversible a través del método de change . Así que tendrás que usar el antiguo método de migración de rieles con up y down

Lee este artículo explica el scenario


En primer lugar, como Jonathan Allard dijo que from y to no están en la fuente del método, lo que significa que change_column_default no lo acepta. Es simplemente así:

def sum(a) return a end

Ahora, si intentas pasarle dos variables como sum(a, b) o cualquier otra cosa, no aceptará ese derecho. Esto es lo que intentas hacer arriba usando from y to .

Ahora la sintaxis correcta de esto es:

change_column_default(:people, :height, 0)

El método no acepta from y to (como se define como tal, incluso si son claves hash, si el método no utiliza ese par de valores clave en cualquier lugar, entonces no tiene ninguna utilidad) y si es un nueva columna, obviamente, tendrá un valor predeterminado nil (si no se configuró antes) y suponga que si la height la columna es de tipo integer y le asigna a valor predeterminado a , almacenará 0 como el valor predeterminado (no estoy seguro al 100% pero he intentado hacerlo) esto desde la consola de rieles). No importa saber cuál es el valor predeterminado actualmente, solo necesita el nuevo valor predeterminado. Entonces, si el valor predeterminado actual es 0 y lo establece en nil rails no se quejará. Es tu base de datos y deseas qué hacer con ella. Solo si la base de datos lo interrumpe si está haciendo algo mal como asignar una string a un boolean , obviamente generará un error.

Ahora, una vez que se ha ejecutado esta migración, se establecerá el valor predeterminado en 0 ahora Rails no sabe cuál fue el valor predeterminado anterior. Como se ha ido y no ha guardado eso en ningún lugar. Por eso, change_column_default es una migración irreversible. Y si intenta revertirlo, le ofrece ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration en caso de change método. Significa cuando has utilizado:

def change change_column_default(:people, :height, 0) end

Por eso es que para este tipo de migraciones usamos el método up y down :

def up change_column_default(:people, :height, 0) end def down change_column_default(:people, :height, nil) end

Espero que esto ayude.


Sólo para añadir algunos puntos. Si está atascado con la versión de Rails que no es compatible con change_column_default reversible, una opción para superar el problema es:

def change # If your dataset is small, just cache in memory, if large, consider file dump here: cache = Table.all # Full column def important for reversibility remove_column :table, :column, :type, { config_hash } # Re-add the column with new default: add_column :table, :column, :type, { config_hash, default: 0 } # Now update the data with cached records (there might be more efficient ways, of course): cache.each do |rec| Table.find(rec.id).update(column: rec.column) end end


Si está utilizando mysql como adaptador, entonces de acuerdo con este enlace http://apidock.com/rails/ActiveRecord/ConnectionAdapters/AbstractMysqlAdapter/change_column_default , su migración change_column_default ejecuta así

def change_column_default(table_name, column_name, default) #:nodoc: column = column_for(table_name, column_name) change_column table_name, column_name, column.sql_type, :default => default end

así que como ve, llama a change_column dentro de sí mismo cuando llama a change_column_default y de acuerdo con este enlace http://edgeguides.rubyonrails.org/active_record_migrations.html change_column migración es irreversible.

Esto muestra por qué obtienes ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration

Entonces, si desea ejecutar la migración utilizando change_column_default , debe agregar def up y def down .

Yo sugeriría usar change_column ya que ya se ha llamado dentro de change_column_default.

def up change_column :people, :height, :integer, default: 0 end def down change_column :people, :height, :integer, default: nil end