Como posso renomear uma coluna de banco de dados em uma migração do Ruby on Rails?

1452

Eu nomeei erroneamente uma coluna em hased_passwordvez de hashed_password.

Como atualizo o esquema do banco de dados, usando a migração para renomear esta coluna?

user1994764
fonte

Respostas:

2309
rename_column :table, :old_column, :new_column

Você provavelmente desejará criar uma migração separada para fazer isso. (Renomeie FixColumnNamecomo quiser.):

script/generate migration FixColumnName
# creates  db/migrate/xxxxxxxxxx_fix_column_name.rb

Em seguida, edite a migração para fazer sua vontade:

# db/migrate/xxxxxxxxxx_fix_column_name.rb
class FixColumnName < ActiveRecord::Migration
  def self.up
    rename_column :table_name, :old_column, :new_column
  end

  def self.down
    # rename back if you need or do something else or do nothing
  end
end

Para o Rails 3.1, use:

Enquanto os métodos upe downainda se aplicam, o Rails 3.1 recebe umachange método que "sabe como migrar seu banco de dados e revertê-lo quando a migração é revertida sem a necessidade de escrever um método separado".

Consulte " Migrações de registros ativos " para obter mais informações.

rails g migration FixColumnName

class FixColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

Se você tiver um monte de colunas para renomear ou algo que exigiria repetir o nome da tabela repetidas vezes:

rename_column :table_name, :old_column1, :new_column1
rename_column :table_name, :old_column2, :new_column2
...

Você pode usar change_tablepara manter as coisas um pouco mais organizadas:

class FixColumnNames < ActiveRecord::Migration
  def change
    change_table :table_name do |t|
      t.rename :old_column1, :new_column1
      t.rename :old_column2, :new_column2
      ...
    end
  end
end

Então, db:migratecomo sempre, ou como você trabalha com seus negócios.


Para Rails 4:

Ao criar um Migrationpara renomear uma coluna, o Rails 4 gera um changemétodo em vez de upe downcomo mencionado na seção acima. O changemétodo gerado é:

$ > rails g migration ChangeColumnName

que criará um arquivo de migração semelhante a:

class ChangeColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
nowk
fonte
24
self.down deve sempre ser o oposto de self.up, portanto, "se você precisar, fazer outra coisa ou não fazer nada" não é realmente recomendado. Basta fazer: rename_column: table_name,: novo_nome_da_coluna,: old_column
Luke Griffiths
3
Embora seja prática normal reverter o que você fez, self.upeu não diria self.down" sempre deve ser o oposto". Depende do contexto da sua migração. Apenas colocar o "oposto" pode não ser a migração "certa" para baixo.
nowk 29/08
23
No Rails 3.1, você pode substituir def self.upe def self.downcom, def changee ele saberá reverter.
Turadg 9/09/11
2
Turadg - * ele saberá reverter a maior parte do tempo. Acho que o changemétodo não é uma prova completa, por isso tendem a usar upe downmétodos para migrações complexas.
JellyFishBoy
6
A renomeação remove o índice?
Sung Cho
68

Na minha opinião, nesse caso, é melhor usar rake db:rollback, editar a migração e executar novamente rake db:migrate.

No entanto, se você tiver dados na coluna que não deseja perder, use rename_column.

elf.xf
fonte
34
Mesmo em uma "equipe de um", se você tiver várias instâncias do seu aplicativo em execução, digamos em diferentes ambientes ou em vários computadores, etc, gerenciar migrações editadas é um grande problema. Só edito uma migração se a criei e percebi que estava errada, e ainda não a execute literalmente em nenhum outro lugar.
Yetanotherjosh
1
Eu tive que reiniciar o servidor depois disso.
Muhammad Hewedy
7
Essa técnica deve ser usada apenas em uma situação em que suas alterações ainda não foram mescladas com sua ramificação de produção e outras não dependem da persistência dos dados. Na maioria das circunstâncias de produção, esse NÃO é o método preferido.
precisa saber é o seguinte
4
nunca faça esse tipo de coisa.
new2cpp 23/02
4
Eu gosto de dizer à minha equipe: 'As migrações são gratuitas' O custo de editar uma migração que foi lançada na natureza é alto: certa vez, passei algumas horas tentando descobrir por que meu código não estava funcionando antes de eu perceber outro membro da equipe havia voltado e editado uma migração que eu já havia executado. Portanto, não edite uma migração existente, use uma nova para alterar o esquema, porque ... ... '' As migrações são gratuitas! ' (não é rigorosamente verdade, mas faz o ponto)
Terrys
31

Se a coluna já estiver preenchida com dados e estiver em produção, recomendo uma abordagem passo a passo, para evitar tempo de inatividade na produção enquanto aguarda as migrações.

Primeiro, eu criaria uma migração de banco de dados para adicionar colunas com os novos nomes e preenchê-los com os valores do nome da coluna antiga.

class AddCorrectColumnNames < ActiveRecord::Migration
  def up
    add_column :table, :correct_name_column_one, :string
    add_column :table, :correct_name_column_two, :string

    puts 'Updating correctly named columns'
    execute "UPDATE table_name SET correct_name_column_one = old_name_column_one, correct_name_column_two = old_name_column_two"
    end
  end

  def down
    remove_column :table, :correct_name_column_one
    remove_column :table, :correct_name_column_two
  end
end

Depois, comprometia exatamente essa mudança e empurrava a mudança para a produção.

git commit -m 'adding columns with correct name'

Então, uma vez que o commit foi colocado em produção, eu executaria.

Production $ bundle exec rake db:migrate

Em seguida, atualizava todas as visualizações / controladores que referenciavam o nome da coluna antiga para o novo nome da coluna. Execute meu conjunto de testes e confirme apenas essas alterações. (Depois de verificar se estava funcionando localmente e passando todos os testes primeiro!)

git commit -m 'using correct column name instead of old stinky bad column name'

Então eu empurrava esse compromisso para a produção.

Nesse ponto, você pode remover a coluna original sem se preocupar com qualquer tipo de tempo de inatividade associado à própria migração.

class RemoveBadColumnNames < ActiveRecord::Migration
  def up
    remove_column :table, :old_name_column_one
    remove_column :table, :old_name_column_two
  end

  def down
    add_column :table, :old_name_column_one, :string
    add_column :table, :old_name_column_two, :string
  end
end

Em seguida, envie essa última migração para a produção e execute bundle exec rake db:migrateem segundo plano.

Sei que isso é um pouco mais envolvido em um processo, mas prefiro fazer isso do que ter problemas com minha migração de produção.

Paul Pettengill
fonte
2
Eu gosto do pensamento por trás disso e gostaria de marcar sua repensagem com +1, mas essa atualização de dados levaria muito tempo para ser executada, pois ela está passando por trilhos e fazendo uma linha por vez. A migração seria executada muito mais rapidamente com instruções sql brutas para atualizar colunas nomeadas corretamente. Por exemplo, no primeiro script de migração db, depois de adicionar os nomes de coluna duplicados, execute "Update table_name set correct_name_column_one = old_name_column_one"
Gui Weinmann
1
@ mr.ruh.roh ^ Concordo totalmente, deveria ter escrito isso em primeiro lugar. Eu editei para refletir uma única instrução sql eficiente. Obrigado pela verificação de sanidade.
Paul Pettengill
2
O que acontece com as entradas entre mover para a nova tabela e atualizar o código para usar a nova tabela? Você não poderia ter dados potencialmente não migrados que sobraram?
Stefan Dorunga
1
embora seja uma resposta 'segura', sinto que está incompleta. Muitas pessoas aqui dizem que não fazem isso - por quê? persistência de dados. E isso é válido. Provavelmente, a maneira menos dolorosa de atingir o objetivo é criar os novos campos, preenchê-los com os dados das colunas antigas e ajustar os controladores. Se você deseja excluir as colunas antigas, certamente precisará editar as visualizações. O custo de mantê-los é um espaço extra de banco de dados e algum esforço duplicado no controlador. As compensações são claras.
Jerome
18

Execute o comando abaixo para criar um arquivo de migração:

rails g migration ChangeHasedPasswordToHashedPassword

Em seguida, no arquivo gerado na db/migratepasta, escreva rename_columncomo abaixo:

class ChangeOldCoulmnToNewColumn < ActiveRecord::Migration
  def change
     rename_column :table_name, :hased_password, :hashed_password
  end
end
Shoaib Malik
fonte
14

Da API:

rename_column(table_name, column_name, new_column_name)

Renomeia uma coluna, mas mantém o tipo e o conteúdo permanece o mesmo.

super_p
fonte
12

Algumas versões do Ruby on Rails suportam o método up / down para a migração e, se você tiver o método up / down na sua migração, então:

def up
    rename_column :table_name, :column_old_name, :column_new_name
end

def down
    rename_column :table_name, :column_new_name, :column_old_name
end

Se você possui o changemétodo em sua migração, então:

def change
    rename_column :table_name, :column_old_name, :column_new_name
end

Para obter mais informações, você pode mover: Ruby on Rails - Migrações ou Migrações do Active Record .

uma
fonte
11

Se o seu código não for compartilhado com outro, a melhor opção é fazer apenas rake db:rollback então editar o nome da coluna na migração e rake db:migrate. É isso aí

E você pode escrever outra migração para renomear a coluna

 def change
    rename_column :table_name, :old_name, :new_name
  end

É isso aí.

tomar sol
fonte
rake db:rollbacké uma ótima sugestão. Mas, como você disse, apenas se a migração ainda não tiver sido enviada.
Danielricecodes
9

Como opção alternativa, se você não é casado com a idéia de migrações, existe uma jóia atraente para o ActiveRecord que manipulará as alterações de nome automaticamente para você, no estilo Datamapper. Tudo o que você faz é alterar o nome da coluna no seu modelo (e certifique-se de colocar Model.auto_upgrade! Na parte inferior do seu model.rb) e viola! O banco de dados é atualizado em tempo real.

https://github.com/DAddYE/mini_record

Nota: Você precisará nuke db / schema.rb para evitar conflitos

Ainda em fase beta e, obviamente, não para todos, mas ainda assim uma opção atraente (atualmente estou usando-o em dois aplicativos de produção não triviais sem problemas)

Steven Garcia
fonte
8

Se você precisar mudar os nomes das colunas, precisará criar um espaço reservado para evitar um erro duplicado no nome da coluna . Aqui está um exemplo:

class SwitchColumns < ActiveRecord::Migration
  def change
    rename_column :column_name, :x, :holder
    rename_column :column_name, :y, :x
    rename_column :column_name, :holder, :y
  end
end
Abram
fonte
7

Se os dados atuais não forem importantes para você, você pode simplesmente cancelar sua migração original usando:

rake db:migrate:down VERSION='YOUR MIGRATION FILE VERSION HERE'

Sem as aspas, faça as alterações na migração original e execute a migração novamente novamente:

rake db:migrate
dirtydexter
fonte
6

Basta criar uma nova migração e, em um bloco, use rename_columncomo abaixo.

rename_column :your_table_name, :hased_password, :hashed_password
Jon Snow
fonte
6

Para Ruby on Rails 4:

def change
    rename_column :table_name, :column_name_old, :column_name_new
end
Hardik Hardiya
fonte
5

Manualmente, podemos usar o método abaixo:

Podemos editar a migração manualmente como:

  • Aberto app/db/migrate/xxxxxxxxx_migration_file.rb

  • Atualizar hased_passwordparahashed_password

  • Execute o comando abaixo

    $> rake db:migrate:down VERSION=xxxxxxxxx

Em seguida, ele removerá sua migração:

$> rake db:migrate:up VERSION=xxxxxxxxx

Ele adicionará sua migração com a alteração atualizada.

Sumit Munot
fonte
não será seguro, pois você poderá perder dados - se a coluna já estiver ativa. mas pode fazer para nova coluna e / ou tabela.
Tejas Patel
5

Gere o arquivo de migração:

rails g migration FixName

# Cria db / migrate / xxxxxxxxxx.rb

Edite a migração para fazer sua vontade.

class FixName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
vipin
fonte
5

Executar rails g migration ChangesNameInUsers(ou o que você quiser nomear)

Abra o arquivo de migração que acabou de ser gerado e adicione esta linha no método (entre def changee end):

rename_column :table_name, :the_name_you_want_to_change, :the_new_name

Salve o arquivo e execute rake db:migrateno console

Verifique o seu schema.dbpara ver se o nome realmente mudou no banco de dados!

Espero que isto ajude :)

Maddie
fonte
5

Vamos BEIJAR . Só é preciso três etapas simples. O seguinte funciona para o Rails 5.2 .

1 Criar uma migração

  • rails g migration RenameNameToFullNameInStudents

  • rails g RenameOldFieldToNewFieldInTableName- dessa forma, é perfeitamente claro para os mantenedores da base de código posteriormente. (use um plural para o nome da tabela).

2. Edite a migração

# I prefer to explicitly write thede cima andpara baixomethods.

# ./db/migrate/20190114045137_rename_name_to_full_name_in_students.rb

class RenameNameToFullNameInStudents < ActiveRecord::Migration[5.2]
  def up
    # rename_column :table_name, :old_column, :new_column
    rename_column :students, :name, :full_name
  end

  def down
            # Note that the columns are reversed
    rename_column :students, :full_name, :name
  end
end

3. Execute suas migrações

rake db:migrate

E você está pronto para as corridas!

BKSpurgeon
fonte
4
$:  rails g migration RenameHashedPasswordColumn
invoke  active_record
      create    db/migrate/20160323054656_rename_hashed_password_column.rb

Abra esse arquivo de migração e modifique-o conforme abaixo (Digite o original table_name)

class  RenameHashedPasswordColumn < ActiveRecord::Migration
  def change
    rename_column :table_name, :hased_password, :hashed_password
  end
end
Prabhakar Undurthi
fonte
4
 def change
    rename_column :table_name, :old_column_name, :new_column_name
  end
Apoorv
fonte
3

Gere uma migração do Ruby on Rails :

$:> rails g migration Fixcolumnname

Insira o código no arquivo de migração (XXXXXfixcolumnname.rb) :

class Fixcolumnname < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
vipin
fonte
2

Abra seu console do Ruby on Rails e digite:

ActiveRecord::Migration.rename_column :tablename, :old_column, :new_column
rinold simon
fonte
2

Você tem duas maneiras de fazer isso:

  1. Nesse tipo, ele executa automaticamente o código reverso, quando é revertido.

    def change
      rename_column :table_name, :old_column_name, :new_column_name
    end
  2. Para esse tipo, ele executa o método up quando rake db:migratee o método down quando rake db:rollback:

    def self.up
      rename_column :table_name, :old_column_name, :new_column_name
    end
    
    def self.down
      rename_column :table_name,:new_column_name,:old_column_name
    end
Sarwan Kumar
fonte
2

Estou no Rails 5.2 e tentando renomear uma coluna em um usuário ideal.

o rename_columnbit funcionou para mim, mas o singular :table_namelançou um erro "Tabela do usuário não encontrada". Plural funcionou para mim.

rails g RenameAgentinUser

Altere o arquivo de migração para este:

rename_column :users, :agent?, :agent

Onde: agente? é o nome da coluna antiga.

túmulo
fonte
0

Atualização - Um primo próximo de create_table é change_table, usado para alterar as tabelas existentes. É usado de maneira semelhante ao create_table, mas o objeto cedido ao bloco conhece mais truques. Por exemplo:

class ChangeBadColumnNames < ActiveRecord::Migration
  def change
    change_table :your_table_name do |t|
      t.rename :old_column_name, :new_column_name
    end
  end
end

Dessa forma, é mais eficiente se o fizermos com outros métodos alter, como: remover / adicionar índice / remover índice / adicionar coluna, por exemplo, podemos fazer outros procedimentos:

# Rename
t.rename :old_column_name, :new_column_name
# Add column
t.string :new_column
# Remove column
t.remove :removing_column
# Index column
t.index :indexing_column
#...
Hieu Pham
fonte
0

Apenas gere a migração usando o comando

rails g migration rename_hased_password

Depois disso, edite a migração, adicione a seguinte linha no método de alteração

rename_column :table, :hased_password, :hashed_password

Isso deve fazer o truque.

Ratnam Yadav
fonte
0

Mudanças na migração do Rails 5

por exemplo:

modelo rails g Student student_name: string age: integer

se você deseja alterar a coluna student_name como nome

Nota: - se você não executar o Rails db: migrate

Você pode seguir os seguintes passos

modelo rails d Aluno student_name: string age: integer

Isso removerá o arquivo de migração gerado. Agora você pode corrigir o nome da sua coluna

modelo rails g Nome do aluno: string age: integer

Se você migrou (rails db: migrate), siga as opções para alterar o nome da coluna

migração rails g RemoveStudentNameFromStudent student_name: string

trilhos g migração AddNameToStudent name: string

prasanthrubyist
fonte
Não deveria ser: rails g migration RemoveStudentNameFromStudentS student_name:string(os alunos são plurais)?
precisa saber é o seguinte
Isso também é perigoso: a coluna não é renomeada, mas totalmente removida e depois lida. O que acontecerá com os dados? Pode não ser o que o usuário deseja.
precisa saber é o seguinte