Agregando: default => true a boolean en la columna Rails existente

160

He visto algunas preguntas (a saber, esta ) aquí en SO sobre agregar un valor booleano predeterminado a una columna existente. Así que probé la change_columnsugerencia pero no debo hacerlo bien.

Lo intenté:

$ change_column :profiles, :show_attribute, :boolean, :default => true

Que vuelve -bash: change_column: command not found

Entonces corrí:

$ rails g change_column :profiles, :show_attribute, :boolean, :default => true

...y

$ rails change_column :profiles, :show_attribute, :boolean, :default => true

Luego corrió rake db:migrate, pero el valor de :show_attributepermaneció nil. En la pregunta que mencioné anteriormente, dice que en PostgreSQL debe actualizarlo manualmente. Como estoy usando PostgreSQL, agregué lo siguiente en mi create_profilesmigración:

t.boolean :show_attribute, :default => true

¿Alguien puede decirme qué estoy haciendo mal aquí?

tvalent2
fuente

Respuestas:

314

change_columnes un método de ActiveRecord::Migration, así que no puedes llamarlo así en la consola.

Si desea agregar un valor predeterminado para esta columna, cree una nueva migración:

rails g migration add_default_value_to_show_attribute

Luego, en la migración creada:

# That's the more generic way to change a column
def up
  change_column :profiles, :show_attribute, :boolean, default: true
end

def down
  change_column :profiles, :show_attribute, :boolean, default: nil
end

O una opción más específica:

def up
    change_column_default :profiles, :show_attribute, true
end

def down
    change_column_default :profiles, :show_attribute, nil
end

Entonces corre rake db:migrate.

No cambiará nada a los registros ya creados. Para hacer eso, tendría que crear rake tasko simplemente ir rails consoley actualizar todos los registros (que no recomendaría en producción).

Cuando agregó t.boolean :show_attribute, :default => truea la create_profilesmigración, se espera que no haya hecho nada. Solo se ejecutan las migraciones que aún no se han ejecutado. Si comenzaste con una nueva base de datos, establecería el valor predeterminado en verdadero.

Robin
fuente
2
Esa llamada change_column debe estar en el upmétodo de la migración, que es una nueva clase que se generará en db / migrate /. (El downmétodo debe escribirse para deshacer lo que uphace.) Realice ese cambio, entonces rake db:migrate.
rkb
Ahh, eso tiene más sentido rkb. ¡Gracias!
tvalent2
no estaba funcionando para mí hasta que escribí def self.upydef self.down
Kamil Szot
Probablemente estés usando una versión anterior de rieles. Creo que esta sintaxis está ahí desde 3.1.
Robin
Y en Rails 5, dejas el atributo _ por lo que debería decir showo el nombre de la columna.
laberinto
95

Como una variación de la respuesta aceptada, también podría usar el change_column_defaultmétodo en sus migraciones:

def up
  change_column_default :profiles, :show_attribute, true
end

def down
  change_column_default :profiles, :show_attribute, nil
end

Rails API-docs

Sebastiaan Pouyet
fuente
1
Esto asegura que no cambiará accidentalmente ninguna de las otras propiedades de la columna
Brian Low
1
Y en Rails 5 dejas el atributo _, por lo que debería decir showo el nombre de la columna.
laberinto
1
@labyrinth ¿Qué quieres decir? show_attribute es el nombre de la columna, no creo que rails 5 tenga nada que ver con eso, ¿verdad?
Robin
34

No estoy seguro de cuándo se escribió esto, pero actualmente para agregar o eliminar un valor predeterminado de una columna en una migración, puede usar lo siguiente:

change_column_null :products, :name, false

Carriles 5:

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

http://edgeguides.rubyonrails.org/active_record_migrations.html#changing-columns

Carriles 4.2:

change_column_default :products, :approved, false

http://guides.rubyonrails.org/v4.2/active_record_migrations.html#changing-columns

Que es una forma ordenada de evitar mirar a través de sus migraciones o esquemas para las especificaciones de la columna.

fbelanger
fuente
Cuidado, es de la documentación de Rails 5. La versión 4.2 de Rails de este no acepta hash, sino exactamente un nuevo valor predeterminado como tercer parámetro. guides.rubyonrails.org/v4.2/…
Clamoris
Acerca de Rails 5, hacer ambas cosas parece ser la forma más correcta, por ejemplo, null: falsey default: :somethingbásicamente
Dorian
1

Si acaba de realizar una migración, puede revertir y luego volver a realizar la migración.

Para revertir puede hacer todos los pasos que desee:

rake db:rollback STEP=1

O, si está utilizando Rails 5.2 o más reciente:

rails db:rollback STEP=1

Luego, puede hacer la migración nuevamente:

def change
  add_column :profiles, :show_attribute, :boolean, default: true
end

No te olvides rake db:migratey si estás usando herokuheroku run rake db:migrate

BM
fuente
0
change_column :things, :price_1, :integer, default: 123, null: false

Parece ser la mejor manera de agregar un valor predeterminado a una columna existente que aún no tiene null: false.

De otra manera:

change_column :things, :price_1, :integer, default: 123

Algunas investigaciones que hice sobre esto:

https://gist.github.com/Dorian/417b9a0e1a4e09a558c39345d50c8c3b

dorio
fuente
0

Si no desea crear otro archivo de migración para un pequeño cambio reciente, desde Rails Console:

ActiveRecord::Migration.change_column :profiles, :show_attribute, :boolean, :default => true

Luego salga y vuelva a ingresar a la consola de rails, por lo que DB-Changes estará en vigor. Entonces, si haces esto ...

Profile.new()

Debería ver el valor predeterminado "show_attribute" como verdadero.

Para los registros existentes, si desea conservar la configuración "falsa" existente y solo actualizar los valores "nulos" a su nuevo valor predeterminado:

Profile.all.each{|profile| profile.update_attributes(:show_attribute => (profile.show_attribute == nil ? true : false))  }

Actualice la migración que creó esta tabla, de modo que cualquier compilación futura de la base de datos lo haga desde el principio. También ejecute el mismo proceso en cualquier instancia desplegada de la base de datos.

Si utiliza el método "nueva migración de db", puede actualizar los valores nulos existentes en esa migración.

JosephK
fuente