Ajout: default => true au booléen dans la colonne Rails existante

160

J'ai vu quelques questions (à savoir celle-ci ) ici sur SO sur l'ajout d'une valeur booléenne par défaut à une colonne existante. J'ai donc essayé la change_columnsuggestion mais je ne dois pas le faire correctement.

J'ai essayé:

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

Quels retours -bash: change_column: command not found

J'ai ensuite couru:

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

...et

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

Puis a couru rake db:migrate, mais la valeur pour :show_attributeest restée nil. Dans la question que j'ai mentionnée ci-dessus, il est dit que dans PostgreSQL, vous devez le mettre à jour manuellement. Depuis que j'utilise PostgreSQL, j'ai ajouté ce qui suit dans ma create_profilesmigration:

t.boolean :show_attribute, :default => true

Quelqu'un peut-il me dire ce que je fais de mal ici?

tvalent2
la source

Réponses:

314

change_columnest une méthode de ActiveRecord::Migration, donc vous ne pouvez pas l'appeler comme ça dans la console.

Si vous souhaitez ajouter une valeur par défaut pour cette colonne, créez une nouvelle migration:

rails g migration add_default_value_to_show_attribute

Puis dans la migration créée:

# 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

OU une option plus spécifique:

def up
    change_column_default :profiles, :show_attribute, true
end

def down
    change_column_default :profiles, :show_attribute, nil
end

Alors courez rake db:migrate.

Cela ne changera rien aux enregistrements déjà créés. Pour ce faire, vous devrez créer un rake taskou simplement aller dans le rails consoleet mettre à jour tous les enregistrements (ce que je ne recommanderais pas en production).

Lorsque vous avez ajouté t.boolean :show_attribute, :default => trueà la create_profilesmigration, on s'attend à ce qu'elle n'ait rien fait. Seules les migrations qui n'ont pas encore été exécutées sont exécutées. Si vous avez commencé avec une nouvelle base de données, la valeur par défaut est true.

Robin
la source
2
Cet appel change_column doit être dans la upméthode de la migration, qui est une nouvelle classe qui sera générée dans db / migrate /. (La downméthode doit être écrite pour annuler ce qui upfait.) Faites ce changement, alors rake db:migrate.
rkb
Ahh, ça a plus de sens rkb. Merci!
tvalent2
cela ne fonctionnait pas pour moi jusqu'à ce que j'écrive def self.upetdef self.down
Kamil Szot
Vous utilisez probablement une ancienne version de rails alors. Je pense que cette syntaxe est là depuis 3.1.
Robin
Et dans Rails 5, vous laissez le _attribute de sorte qu'il devrait simplement dire showou quel que soit le nom de la colonne.
labyrinthe
95

Comme variante de la réponse acceptée, vous pouvez également utiliser la change_column_defaultméthode dans vos migrations:

def up
  change_column_default :profiles, :show_attribute, true
end

def down
  change_column_default :profiles, :show_attribute, nil
end

Documentation sur l'API Rails

Sebastiaan Pouyet
la source
1
Cela garantit que vous ne modifierez accidentellement aucune des autres propriétés de la colonne
Brian Low
1
Et dans Rails 5, vous laissez le _attribute désactivé pour qu'il dise simplement showou quel que soit le nom de la colonne.
labyrinthe
1
@labyrinth Que voulez-vous dire? show_attribute est le nom de la colonne, je ne pense pas que rails 5 ait quoi que ce soit à voir avec ça, non?
Robin
34

Je ne sais pas quand cela a été écrit, mais actuellement pour ajouter ou supprimer une valeur par défaut d'une colonne dans une migration, vous pouvez utiliser ce qui suit:

change_column_null :products, :name, false

Rails 5:

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

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

Rails 4.2:

change_column_default :products, :approved, false

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

Ce qui est un bon moyen d'éviter de parcourir vos migrations ou votre schéma pour les spécifications de colonne.

fbelanger
la source
Attention, c'est de la documentation Rails 5. La version 4.2 de Rails n'accepte pas le hachage mais exactement la nouvelle valeur par défaut comme troisième paramètre. guides.rubyonrails.org/v4.2/…
Clamoris
À propos de Rails 5, faire les deux semble être la manière la plus correcte, par exemple null: falseet default: :somethingfondamentalement
Dorian
1

Aussi, selon le doc:

la valeur par défaut ne peut pas être spécifiée via la ligne de commande

https://guides.rubyonrails.org/active_record_migrations.html

Il n'y a donc pas de générateur de rails prêt à l'emploi. Comme spécifié par les réponses ci-dessus, vous devez remplir manuellement votre fichier de migration avec la change_column_defaultméthode.

Vous pouvez créer votre propre générateur: https://guides.rubyonrails.org/generators.html

Margotte
la source
1

Si vous venez d'effectuer une migration, vous pouvez revenir en arrière, puis effectuer à nouveau votre migration.

Pour revenir en arrière, vous pouvez effectuer autant d'étapes que vous le souhaitez:

rake db:rollback STEP=1

Ou, si vous utilisez Rails 5.2 ou plus récent:

rails db:rollback STEP=1

Ensuite, vous pouvez simplement refaire la migration:

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

N'oubliez pas rake db:migrateet si vous utilisez herokuheroku run rake db:migrate

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

Semble être le meilleur moyen d'ajouter une valeur par défaut à une colonne existante qui ne l'a pas null: falsedéjà.

Autrement:

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

Quelques recherches que j'ai faites à ce sujet:

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

Dorian
la source
0

Si vous ne souhaitez pas créer un autre fichier de migration pour une petite modification récente - à partir de Rails Console:

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

Puis quittez et entrez à nouveau dans la console des rails, ainsi les changements de base de données seront appliqués. Ensuite, si vous faites cela ...

Profile.new()

Vous devriez voir la valeur par défaut "show_attribute" comme true.

Pour les enregistrements existants, si vous souhaitez conserver les paramètres "faux" existants et ne mettre à jour que les valeurs "nil" avec votre nouvelle valeur par défaut:

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

Mettez à jour la migration qui a créé cette table, de sorte que toutes les futures versions de la base de données l'obtiennent dès le début. Exécutez également le même processus sur toutes les instances déployées de la base de données.

Si vous utilisez la méthode "new db migration", vous pouvez effectuer la mise à jour des valeurs nulles existantes dans cette migration.

JosephK
la source