Selon le joyau Strong Migrations , l'utilisation change_column_null
en production est une mauvaise idée car elle bloque les lectures et les écritures pendant que tous les enregistrements sont vérifiés.
La méthode recommandée pour gérer ces migrations (spécifiques à Postgres) consiste à séparer ce processus en deux migrations.
Un pour modifier la table avec la contrainte:
class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
def change
safety_assured do
execute 'ALTER TABLE "users" ADD CONSTRAINT "users_some_column_null" CHECK ("some_column" IS NOT NULL) NOT VALID'
end
end
end
Et une migration séparée pour le valider:
class ValidateSomeColumnNotNull < ActiveRecord::Migration[6.0]
def change
safety_assured do
execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "users_some_column_null"'
end
end
end
Les exemples ci-dessus sont extraits (et légèrement modifiés) de la documentation liée. Apparemment, pour Postgres 12+, vous pouvez également ajouter NOT NULL
au schéma, puis supprimer la contrainte après l'exécution de la validation:
class ValidateSomeColumnNotNull < ActiveRecord::Migration[6.0]
def change
safety_assured do
execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "users_some_column_null"'
end
change_column_null :users, :some_column, false
safety_assured do
execute 'ALTER TABLE "users" DROP CONSTRAINT "users_some_column_null"'
end
end
end
Naturellement, cela signifie que votre schéma ne montrera pas que la colonne est NOT NULL
pour les versions antérieures de Postgres, donc je vous conseille également de définir une validation au niveau du modèle pour exiger que la valeur soit présente (bien que je suggère la même chose même pour les versions de PG qui permettent cette étape).
En outre, avant d'exécuter ces migrations, vous souhaiterez mettre à jour tous les enregistrements existants avec une valeur autre que null et vous assurer que tout code de production qui écrit dans la table n'écrit pas null
pour la ou les valeurs.
MyModel.update_all({:date_column => Time.now}, {:date_column => nil})
. La requête dans votre forme originale vient de faire en sorte que tous mes modèles aient une valeur nulle dans le champ.