web-dev-qa-db-fra.com

Comment changer une colonne nullable en non nullable dans une migration Rails?

J'ai créé une colonne de date dans une migration précédente et je l'ai définie sur nullable. Maintenant, je veux changer pour ne pas être annulable. Comment puis-je faire cela en supposant qu'il y a 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.

176
Kevin Pang

Si vous le faites dans une migration, vous pouvez probablement le faire comme ceci:

# 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
189
DanneManne

Dans Rails 4, il s'agit d'une meilleure solution (DRYer):

change_column_null :my_models, :date_column, false

Pour vous assurer qu'aucun enregistrement n'existe avec les valeurs NULL dans cette colonne, vous pouvez passer un quatrième paramètre, qui est la valeur par défaut à utiliser pour les enregistrements avec les valeurs NULL:

change_column_null :my_models, :date_column, false, Time.now
145
mrbrdo

Rails 4 (other Rails 4 réponses 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 afin de ne pas autoriser NULL entraînera 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 [~ # ~] live [~ # ~] production. Vous devez d’abord modifier les valeurs NULL en valeurs valides et , puis interdire les valeurs NULL. La 4ème valeur dans change_column_null fait exactement cela. Voir documentation pour plus de détails.

En outre, 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 aussi.

66
Rick Smith

Créez une migration qui a un change_column déclaration avec un :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

32
jessecurry

Rails 4:

def change
  change_column_null(:users, :admin, false )
end
11
piratebroadcast

Dans Rails 4.02 + selon docs il n’existe 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
3
jmarceli

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
2
Nicolas Maloeuvre