ruby-on-rails database sqlite3 sqlite3-ruby

ruby on rails - ¿Cómo resolver "No se puede agregar una columna NOT NULL con el valor predeterminado NULL" en SQLite3?



ruby-on-rails database (3)

Esto es (lo que yo consideraría) una falla con SQLite. Este error se produce si hay registros en la tabla o no.

Al agregar una tabla desde cero, puede especificar NOT NULL, que es lo que está haciendo con la notación ": null => false". Sin embargo, no puede hacer esto al agregar una columna. La especificación de SQLite dice que tiene que tener un valor predeterminado para esto, que es una mala elección. Agregar un valor predeterminado no es una opción porque anula el propósito de tener una clave foránea NO NULA, es decir, la integridad de los datos.

Aquí hay una manera de evitar este problema, y ​​puede hacerlo todo en la misma migración. NOTA: esto es para el caso en el que aún no tiene registros en la base de datos.

class AddDivisionIdToProfile < ActiveRecord::Migration def self.up add_column :profiles, :division_id, :integer change_column :profiles, :division_id, :integer, :null => false end def self.down remove_column :profiles, :division_id end end

Estamos agregando la columna sin la restricción NOT NULL, y luego la alteramos inmediatamente para agregar la restricción. Podemos hacer esto porque si bien SQLite aparentemente está muy preocupado durante un agregado de columna, no es tan delicado con los cambios de columna. Este es un claro olor a diseño en mi libro.

Definitivamente es un truco, pero es más corto que múltiples migraciones y aún funcionará con bases de datos SQL más robustas en su entorno de producción.

Recibo el siguiente error al intentar agregar una columna NOT NULL a una tabla existente. ¿Por qué está sucediendo? Intenté rake db: reset pensando que los registros existentes son el problema, pero incluso después de reiniciar el DB, el problema persiste. ¿Puedes por favor ayudarme a resolver esto?

Archivo de migración

class AddDivisionIdToProfile < ActiveRecord::Migration def self.up add_column :profiles, :division_id, :integer, :null => false end def self.down remove_column :profiles, :division_id end end

Mensaje de error

SQLite3 :: SQLException: No se puede agregar una columna NOT NULL con el valor predeterminado NULL: ALTER TABLE "perfiles" ADD "division_id" entero NOT NULL


Si tiene una tabla con filas existentes, deberá actualizar las filas existentes antes de agregar su restricción null . La Guía sobre migraciones recomienda usar un modelo local, como por ejemplo:

Rieles 4 y superiores:

class AddDivisionIdToProfile < ActiveRecord::Migration class Profile < ActiveRecord::Base end def change add_column :profiles, :division_id, :integer Profile.reset_column_information reversible do |dir| dir.up { Profile.update_all division_id: Division.first.id } end change_column :profiles, :division_id, :integer, :null => false end end

Rieles 3

class AddDivisionIdToProfile < ActiveRecord::Migration class Profile < ActiveRecord::Base end def change add_column :profiles, :division_id, :integer Profile.reset_column_information Profile.all.each do |profile| profile.update_attributes!(:division_id => Division.first.id) end change_column :profiles, :division_id, :integer, :null => false end end


Ya tiene filas en la tabla y está agregando una nueva columna division_id . Necesita algo en esa nueva columna en cada una de las filas existentes.

SQLite normalmente elegiría NULL, pero ha especificado que no puede ser NULL, entonces, ¿qué debería ser? No tiene forma de saberlo.

Consulte Adición de una columna no nula sin valor predeterminado en una migración de Rails

La recomendación de ese blog es agregar la columna sin la restricción no nula, y se agregará con NULL en cada fila. Luego puede completar los valores en el division_id y luego usar change_column para agregar la restricción no nula.

Vea el blog al que me he vinculado para ver un ejemplo de un script de migración que realiza este proceso de tres pasos.