Agregar un valor predeterminado a una columna a través de una migración

276

¿Cómo agrego un valor predeterminado a una columna que ya existe a través de una migración?

Toda la documentación que puedo encontrar le muestra cómo hacerlo si la columna aún no existe, pero en este caso sí.

Jon
fuente

Respuestas:

352

Así es como debes hacerlo:

change_column :users, :admin, :boolean, :default => false

Pero algunas bases de datos, como PostgreSQL, no actualizarán el campo para las filas creadas previamente, así que asegúrese de actualizar el campo también en la migración.

Maurício Linhares
fuente
14
Si necesita migraciones reversibles, colóquelo en un upbloque en lugar de un changebloque. Puedes dejar el downbloque vacío. No revertirá la tabla a la condición original, pero la migración puede revertirse.
IAmNaN
1
¿Esto mantendrá los datos intactos?
Marco Prins
2
En PostgreSQL, sí, no sé qué pasará en otras bases de datos.
Maurício Linhares
1
¿Qué quiere decir cuando dice "asegúrese de actualizar el campo manualmente en la migración"? ¿Cómo se hace eso?
David Argyle Thacker
77
Lo probé en PostgreSQL y actualizó los campos creados previamente.
Aboozar Rajabi
190
change_column_default :employees, :foreign, false
Gazza
fuente
1
@DenisLins Estuve de acuerdo con usted, así que investigué un poco para descubrir por qué podría no ser así, y resulta que existe la posibilidad de que un adaptador de base de datos en particular no lo admita, ya que se implementa a ese nivel. La respuesta aceptada sigue siendo la apuesta más segura hasta que se implemente en el modelo abstracto. apidock.com/rails/ActiveRecord/ConnectionAdapters/…
natchiketa
55
Además de eso, es necesario especificar una from:y to:si usted quiere que sea reversible :)
radubogdan
55
Usando fromy tose agregó en Rails 5+ en esta confirmación: github.com/rails/rails/pull/20018/files
Joshua Pinter
115

Para Rails 4+ , usechange_column_default

def change
  change_column_default :table, :column, value
end
csi
fuente
1
Esto es excelente, especialmente si tiene una migración que agrega una columna y establece valores predeterminados para los registros existentes. Por ejemplo: def change `add_column: foos,: name, default:" algo para valores existentes "` `change_column_default: foos,: name, default:" "`end
user1491929
2
Esta migración tiene un comportamiento extraño. En el tuyo, es irreversible. edgeguides.rubyonrails.org/active_record_migrations.html recomienda usarlo de esta manera: change_column_default :products, :approved, from: true, to: false- pero tampoco funciona.
Ilya Krigouzov
no puede retroceder usando eso?
aldrien.h
Por lo general, sí, para casi cualquier cláusula "Cambiar", ya que todos los estados anteriores suelen ser explícitos, como la presencia de una columna, su tipo, etc. El cambio se puede revertir como se muestra allí si y solo si hubo una válido por defecto explícito previamente. Como es común que los valores predeterminados no estén definidos, es posible que tenga un problema allí.
Elindor
48

Usar def changesignifica que debe escribir migraciones que sean reversibles. Y change_columnno es reversible. Puedes subir pero no puedes bajar, ya que change_columnes irreversible.

En cambio, aunque puede ser un par de líneas adicionales, debe usar def upydef down

Entonces, si tiene una columna sin valor predeterminado, debe hacer esto para agregar un valor predeterminado.

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: nil
end

O si desea cambiar el valor predeterminado para una columna existente.

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: true
end
bfcoder
fuente
37

** Rieles 4.X + **

A partir de Rails 4, no puede generar una migración para agregar una columna a una tabla con un valor predeterminado. Los siguientes pasos agregan una nueva columna a una tabla existente con el valor predeterminado verdadero o falso.

1. Ejecute la migración desde la línea de comando para agregar la nueva columna

$ rails generate migration add_columnname_to_tablename columnname:boolean

El comando anterior agregará una nueva columna en su tabla.

2. Establezca el nuevo valor de columna en VERDADERO / FALSO editando el nuevo archivo de migración creado.

class AddColumnnameToTablename < ActiveRecord::Migration
  def change
    add_column :table_name, :column_name, :boolean, default: false
  end
end

** 3. Para realizar los cambios en la tabla de la base de datos de la aplicación, ejecute el siguiente comando en la terminal **

$ rake db:migrate
Praveen George
fuente
¿En qué se diferencia esto de los rieles 3+ o 2+?
Ruby Racer
2
¿Alguien sabe si esto se ha incorporado a Rails 5?
sambecker
9

Ejecutar:

rails generate migration add_column_to_table column:boolean

Generará esta migración:

class AddColumnToTable < ActiveRecord::Migration
  def change
    add_column :table, :column, :boolean
  end
end

Establezca el valor predeterminado agregando: default => 1

add_column: table,: column,: boolean,: default => 1

Correr:

rastrillo db: migrar

axeltaglia
fuente
2
Ahora el valor predeterminado de 1 no es exactamente un booleano;) Además, este examen agrega una nueva columna, en lugar de cambiar la columna existente, que es lo que el OP quería lograr
radiospiel
@radiospiel En realidad, 1 también es booleano :)
kinduff
También deberá crear un registro en la tabla de claves externas con un ID de 1 para que esto funcione, para evitar el Key is not present in table error.
Promesa Preston
-50

Esto es lo que puedes hacer:

class Profile < ActiveRecord::Base
  before_save :set_default_val

  def set_default_val
    self.send_updates = 'val' unless self.send_updates
  end
end

EDITAR: ... pero aparentemente este es un error de novato!

novatoRailer
fuente
Es mejor si establece el valor predeterminado en el esquema vs como unbefore_save
rigelstpierre
66
Qué sugerencia terrible
svelandiag
de acuerdo, es realmente terrible
Houcheng
3
ouch, tienes mucho calor por hacer algo a nivel de modelo en lugar de a nivel de base de datos. -38 es un puntaje legendario.
nurettin
1
lo que es un error de novato ... ;-)
webaholik