Coluna de migração de trilhos para mudança

327

Temos script/generate migration add_fieldname_to_tablename fieldname:datatypesintaxe para adicionar novas colunas a um modelo.

Na mesma linha, temos um script / generate para alterar o tipo de dados de uma coluna? Ou devo escrever SQL diretamente na minha migração de baunilha?

Eu quero mudar uma coluna de datetimepara date.

papdel
fonte

Respostas:

549

Eu acho que isso deve funcionar.

change_column :table_name, :column_name, :date
Alex Korban
fonte
13
@b_ayan: até onde eu sei, as únicas palavras mágicas nos nomes de migração são "adicionar" e "remover".
quer
1
Tipo de trilhos noob aqui, mas ... eu entendo a resposta, mas não os comentários sobre esta resposta. Esclarecimentos apreciados :)
Alan H.
7
Ao criar uma migração, você fornece um nome (por exemplo, add_fieldname_to_tablename na pergunta acima). Se começar com "adicionar" ou "remover", a migração será automaticamente preenchida com o código para adicionar ou remover colunas, o que poupa você a escrever esse código.
Alex Korban
6
Também é importante ter em mente que você deve substituir a changeação usual por separada upe downações, pois change_columné uma migração irreversível e causará um erro caso você precise reverter.
DaveStephens
1
@QPaysTaxes up deve conter o que você deseja alterar sua coluna de e para e down deve conter como reverter essa alteração.
precisa saber é o seguinte
98

Você também pode usar um bloco se tiver várias colunas para alterar em uma tabela.

Exemplo:

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

Consulte a documentação da API na classe Table para obter mais detalhes.

John
fonte
88

Não sei se é possível criar uma migração a partir da linha de comando para fazer tudo isso, mas é possível criar uma nova migração e editar a migração para executar essas tarefas.

Se tablename é o nome da sua tabela, fieldname é o nome do seu campo e você deseja alterar de data e hora para data, você pode escrever uma migração para fazer isso.

Você pode criar uma nova migração com:

rails g migration change_data_type_for_fieldname

Em seguida, edite a migração para usar 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

Em seguida, execute a migração:

rake db:migrate
Ryan
fonte
32

Como descobri pelas respostas anteriores, são necessárias três etapas para alterar o tipo de uma coluna:

Passo 1:

Gere um novo arquivo de migração usando este código:

rails g migration sample_name_change_column_type

Passo 2:

Vá para a /db/migratepasta e edite o arquivo de migração que você criou. Existem duas soluções diferentes.

  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

Etapa 3:

Não esqueça de executar este comando:

rake db:migrate

Eu testei esta solução para o Rails 4 e funciona bem.

Aboozar Rajabi
fonte
1
Na etapa 2, a primeira falhará depois de executar o rake db: rollback, eu recomendo que você verifique a segunda.
Feuda
Existe uma convenção de trilhos que permite que tudo seja feito mais ou menos ao gerar o arquivo de migração sem precisar ir e editá-lo?
precisa saber é o seguinte
@BKSpurgeon Sim, verifique a documentação aqui: edgeguides.rubyonrails.org/active_record_migrations.html
Aboozar Rajabi
12

Com trilhos 5

Nos Guias do Rails :

Se você deseja que uma migração faça algo que o Active Record não sabe reverter, você pode usar 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
Mr. Tao
fonte
8

Basta gerar migração:

rails g migration change_column_to_new_from_table_name

Atualize a migração assim:

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

e finalmente

rake db:migrate
Vivek Sharma
fonte
2

Outra maneira de alterar o tipo de dados usando a migração

etapa1: você precisa remover o nome do campo do tipo de dados com falha usando a migração

ex:

rails g migration RemoveFieldNameFromTableName field_name:data_type

Aqui não se esqueça de especificar o tipo de dados para o seu campo

Etapa 2: agora você pode adicionar um campo com o tipo de dados correto

ex:

rails g migration AddFieldNameToTableName field_name:data_type

É isso aí, agora sua tabela será adicionada com o campo de tipo de dados correto, Happy ruby ​​coding !!

prasanthrubyist
fonte
2

Isso tudo pressupõe que o tipo de dados da coluna tenha uma conversão implícita para quaisquer dados existentes. Eu já tive várias situações em que os dados existentes, digamos, Stringpodem ser implicitamente convertidos no novo tipo de dados, digamos Date.

Nessa situação, é útil saber que você pode criar migrações com conversões de dados. Pessoalmente, gosto de colocá-las no meu arquivo de modelo e removê-las depois que todos os esquemas do banco de dados foram migrados e estão estáveis.

/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
Sebastian Scholl
fonte
0

Para concluir as respostas em caso de edição do valor padrão :

No seu console de trilhos:

rails g migration MigrationName

Na migração:

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

Vai parecer :

  def change
    change_column :members, :approved, :boolean, default: true
  end
Gregdebrick
fonte