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