Migrazione delle rotaie per la colonna di modifica


327

Abbiamo una script/generate migration add_fieldname_to_tablename fieldname:datatypesintassi per aggiungere nuove colonne a un modello.

Sulla stessa linea, abbiamo uno script / generate per cambiare il tipo di dati di una colonna? O dovrei scrivere SQL direttamente nella mia migrazione alla vaniglia?

Voglio cambiare una colonna da datetimea date.

Risposte:


549

Penso che dovrebbe funzionare.

change_column :table_name, :column_name, :date

13
@b_ayan: per quanto ne so, le uniche parole magiche nei nomi delle migrazioni sono "aggiungi" e "rimuovi".
Alex Korban,

1
Una specie di binario qui, ma ... Capisco la risposta ma non i commenti su questa risposta. Chiarimenti apprezzati :)
Alan H.

7
Quando si crea una migrazione, si assegna un nome (ad es. Add_fieldname_to_tablename nella domanda sopra). Se inizia con "aggiungi" o "rimuovi", la migrazione verrà automaticamente popolata con il codice per aggiungere o rimuovere colonne, il che ti farà risparmiare scrivendo tu stesso quel codice.
Alex Korban,

6
Vale anche la pena ricordare che è necessario sostituire la normale changeazione con azioni separate upe downazioni, in quanto si change_columntratta di una migrazione irreversibile e genererà un errore nel caso in cui sia necessario eseguire il rollback.
DaveStephens,

1
@QPaysTaxes up dovrebbe contenere ciò che vuoi cambiare la tua colonna da e a, e down dovrebbe contenere come invertire quella modifica.
DaveStephens,

98

Puoi anche usare un blocco se hai più colonne da modificare all'interno di una tabella.

Esempio:

change_table :table_name do |t|
  t.change :column_name, :column_type, {options}
end

Vedere la documentazione dell'API sulla classe Table per ulteriori dettagli.


88

Non so se è possibile creare una migrazione dalla riga di comando per fare tutto questo, ma è possibile creare una nuova migrazione, quindi modificare la migrazione per eseguire questa operazione.

Se tablename è il nome della tabella, fieldname è il nome del campo e si desidera cambiare da un datetime a oggi, è possibile scrivere una migrazione per farlo.

Puoi creare una nuova migrazione con:

rails g migration change_data_type_for_fieldname

Quindi modifica la migrazione per utilizzare change_table:

class ChangeDataTypeForFieldname < ActiveRecord::Migration
  def self.up
    change_table :tablename do |t|
      t.change :fieldname, :date
    end
  end
  def self.down
    change_table :tablename do |t|
      t.change :fieldname, :datetime
    end
  end
end

Quindi eseguire la migrazione:

rake db:migrate

32

Come ho trovato nelle risposte precedenti, sono necessari tre passaggi per modificare il tipo di una colonna:

Passo 1:

Genera un nuovo file di migrazione usando questo codice:

rails g migration sample_name_change_column_type

Passo 2:

Vai alla /db/migratecartella e modifica il file di migrazione che hai creato. Esistono due diverse soluzioni.

  1. def change
        change_column(:table_name, :column_name, :new_type)
    end

2.

    def up
        change_column :table_name, :column_name, :new_type
    end

    def down
        change_column :table_name, :column_name, :old_type
    end

Passaggio 3:

Non dimenticare di eseguire questo comando:

rake db:migrate

Ho testato questa soluzione per Rails 4 e funziona bene.


1
Nel passaggio 2, il primo fallirà dopo aver eseguito il rake db: rollback, ti ​​consiglio di controllare il secondo
Feuda

Esiste una convenzione di rotaie che consente di fare più o meno tutto quando si genera il file di migrazione senza accedervi e quindi modificarlo?
BKSpurgeon,

@BKSpurgeon Sì, controlla la documentazione qui: edgeguides.rubyonrails.org/active_record_migrations.html
Aboozar Rajabi,

12

Con binari 5

Dalle guide di Rails :

Se desideri che una migrazione faccia qualcosa che Active Record non sa come invertire, puoi usare reversible:

class ChangeTablenameFieldname < ActiveRecord::Migration[5.1]
  def change
    reversible do |dir|
      change_table :tablename do |t|
        dir.up   { t.change :fieldname, :date }
        dir.down { t.change :fieldname, :datetime }
      end
    end
  end
end

8

Basta generare la migrazione:

rails g migration change_column_to_new_from_table_name

Aggiorna la migrazione in questo modo:

class ClassName < ActiveRecord::Migration
  change_table :table_name do |table|
    table.change :column_name, :data_type
  end
end

e infine

rake db:migrate

2

Un altro modo per modificare il tipo di dati mediante la migrazione

step1: È necessario rimuovere il nome del campo del tipo di dati con errori utilizzando la migrazione

ex:

rails g migration RemoveFieldNameFromTableName field_name:data_type

Qui non dimenticare di specificare il tipo di dati per il tuo campo

Passaggio 2: ora è possibile aggiungere un campo con il tipo di dati corretto

ex:

rails g migration AddFieldNameToTableName field_name:data_type

Ecco fatto, ora la tua tabella verrà aggiunta con il campo del tipo di dati corretto, Happy ruby ​​coding !!


2

Tutto questo presuppone che il tipo di dati della colonna abbia una conversione implicita per tutti i dati esistenti. Ho incontrato diverse situazioni in cui i dati esistenti, supponiamo che a Stringpossano essere implicitamente convertiti nel nuovo tipo di dati, diciamo Date.

In questa situazione, è utile sapere che è possibile creare migrazioni con conversioni di dati. Personalmente, mi piace inserirli nel mio file modello e quindi rimuoverli dopo che tutti gli schemi di database sono stati migrati e sono stabili.

/app/models/table.rb
  ...
  def string_to_date
    update(new_date_field: date_field.to_date)
  end

  def date_to_string
    update(old_date_field: date_field.to_s)
  end
  ...
    def up
        # Add column to store converted data
        add_column :table_name, :new_date_field, :date
        # Update the all resources
        Table.all.each(&:string_to_date)
        # Remove old column
        remove_column :table_name, :date_field
        # Rename new column
        rename_column :table_name, :new_date_field, :date_field
    end

    # Reversed steps does allow for migration rollback
    def down
        add_column :table_name, :old_date_field, :string
        Table.all.each(&:date_to_string)
        remove_column :table_name, :date_field
        rename_column :table_name, :old_date_field, :date_field
    end

0

Per completare le risposte in caso di modifica del valore predefinito :

Nella tua console di binari:

rails g migration MigrationName

Nella migrazione:

  def change
    change_column :tables, :field_name, :field_type, default: value
  end

Apparirà come:

  def change
    change_column :members, :approved, :boolean, default: true
  end
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.