J'ai créé une colonne de date dans une migration précédente et je l'ai définie comme nullable. Maintenant, je veux le changer pour qu'il ne puisse pas être annulé. Comment procéder en supposant qu'il existe des lignes nulles dans cette base de données? Je suis d'accord pour définir ces colonnes sur Time.now si elles sont actuellement nulles.
ruby-on-rails
migration
Kevin Pang
la source
la source
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.change
méthode n'est pas si adaptée à ce cas car (1) laupdate_all
méthode sera exécutée à la fois lors de la migration et d'un retour potentiel. Ce n'est peut-être pas la pire des choses, mais parce que (2) la migration n'a aucun moyen de savoir de quoi la colonne a été modifiée lors d'un retour potentiel. Donc, pour ce cas, je m'en tiendrai àup
etdown
.Dans Rails 4, c'est une meilleure solution (DRYer):
change_column_null :my_models, :date_column, false
Pour vous assurer qu'aucun enregistrement n'existe avec des
NULL
valeurs dans cette colonne, vous pouvez transmettre un quatrième paramètre, qui est la valeur par défaut à utiliser pour les enregistrements avec desNULL
valeurs:change_column_null :my_models, :date_column, false, Time.now
la source
change_column_null
. Cependant, le commentaire de Rick Smith ci-dessus souligne un cas très valable.Rails 4 (les autres réponses Rails 4 ont des problèmes):
def change change_column_null(:users, :admin, false, <put a default value here> ) # change_column(:users, :admin, :string, :default => "") end
La modification d'une colonne contenant des valeurs NULL pour ne pas autoriser NULL posera des problèmes. C'est exactement le type de code qui fonctionnera correctement dans votre configuration de développement, puis se bloquera lorsque vous tenterez de le déployer sur votre production LIVE . Vous devez d'abord changer les valeurs NULL en quelque chose de valide, puis interdire les NULL. La 4ème valeur dans
change_column_null
fait exactement cela. Consultez la documentation pour plus de détails.De plus, je préfère généralement définir une valeur par défaut pour le champ afin de ne pas avoir besoin de spécifier la valeur du champ chaque fois que je crée un nouvel objet. J'ai inclus le code commenté pour le faire également.
la source
add_column :users, :admin, :string
thenchange_column_null(:admin, :string, false, "new_value_for_existing_records")
Créez une migration qui a une
change_column
instruction avec une:default =>
valeur.change_column :my_table, :my_column, :integer, :default => 0, :null => false
Voir: change_column
En fonction du moteur de base de données, vous devrez peut-être utiliser
change_column_null
la source
change_column_null
.Rails 4:
def change change_column_null(:users, :admin, false ) end
la source
Dans Rails 4.02+, selon la documentation, il n'y a pas de méthode comme
update_all
avec 2 arguments. Au lieu de cela, on peut utiliser ce code:# Make sure no null value exist MyModel.where(date_column: nil).update_all(date_column: Time.now) # Change the column to not allow null change_column :my_models, :date_column, :datetime, null: false
la source
Vous ne pouvez pas utiliser add_timestamps et null: false si vous avez des enregistrements existants, voici donc la solution:
def change add_timestamps(:buttons, null: true) Button.find_each { |b| b.update(created_at: Time.zone.now, updated_at: Time.zone.now) } change_column_null(:buttons, :created_at, false) change_column_null(:buttons, :updated_at, false) end
la source
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 # in Postgres 12+, you can then safely set NOT NULL on the column 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.la source