Como você escreve uma migração para renomear um modelo ActiveRecord e sua tabela no Rails?

408

Sou péssimo em nomear e percebo que há um conjunto melhor de nomes para meus modelos no meu aplicativo Rails.
Existe alguma maneira de usar uma migração para renomear um modelo e sua tabela correspondente?

Somente leitura
fonte
11
Sugeri adicionar "ActiveRecord" a esta pergunta para melhorar as correspondências dos mecanismos de pesquisa. Eu estive procurando isso usando "ActiveRecord renomear tabela".
Landon Kuhn /
6
Se você estiver usando migrações, esse problema é mais complicado do que parece. A solução selecionada diz para voltar e renomear manualmente o modelo, o controlador etc. depois de alterar o nome da tabela. Se você fizer isso, todas as migrações mais antigas que se referem ao seu modelo pelo nome mais antigo falharão. Portanto, quando alguém clona seu repositório e tenta executar rake db:migrate, ele falha. Você pode voltar e alterar esses nomes na migração, mas isso ficará confuso. É melhor criar um modelo inteiramente novo do que renomeá-lo.
22612 Andrew Andrew
4
@andrewhannigan: O seu ponto não é discutível se alguém clona seu repositório e apenas executa rake db:schema:load?
istrasci
3
@istrasci: absolutamente. De fato, correr rake db:migratepara configurar um banco de dados a partir do zero é desencorajado ativamente, exatamente por causa das preocupações apontadas por andrew.
Giuseppe

Respostas:

584

Aqui está um exemplo:

class RenameOldTableToNewTable < ActiveRecord::Migration
  def self.up
    rename_table :old_table_name, :new_table_name
  end

  def self.down
    rename_table :new_table_name, :old_table_name
  end
end

Eu tive que mudar o nome do arquivo de declaração do modelo manualmente.

Editar:

No Rails 3.1 e 4, ActiveRecord::Migration::CommandRecordersabe como reverter as migrações rename_table, para que você possa fazer isso:

class RenameOldTableToNewTable < ActiveRecord::Migration
  def change
    rename_table :old_table_name, :new_table_name
  end 
end

(Você ainda precisa passar por e renomear seus arquivos manualmente.)

Somente leitura
fonte
6
@mathee: sim, você precisa alterar isso manualmente ou usar um IDE que possa refatorar o Ruby e enviá-lo ao seu sistema de controle de versão.
pupeno
13
git grep é seu amigo. Estou renomeando uma atividade para um hábito agora: git grep -i activité muito revelador.
Felix Rabe
1
você também precisa alterar o conteúdo do seu controlador, certo?
alemur 2/02/12
5
E não se esqueça das suas rotas.rb!
Dan Herman
26
Além disso, como um alerta, você deseja usar a versão plural do nome da sua tabela na chamada rename_table.
Han
66

No Rails 4, tudo o que eu precisava fazer era a alteração da definição

def change
  rename_table :old_table_name, :new_table_name
end

E todos os meus índices foram resolvidos por mim. Não precisei atualizar manualmente os índices removendo os antigos e adicionando novos.

E funciona usando a alteração para subir ou descer em relação aos índices também.

bfcoder
fonte
47

As outras respostas e comentários abordaram a renomeação de tabelas, renomeação de arquivos e grepping através do seu código.

Gostaria de adicionar mais algumas advertências:

Vamos usar um exemplo do mundo real que eu enfrentei hoje: renomear um modelo de 'Merchant' para 'Business'.

  • Não se esqueça de alterar os nomes de tabelas e modelos dependentes na mesma migração. Alterei meus modelos Merchant e MerchantStat para Business e BusinessStat ao mesmo tempo. Caso contrário, eu teria que escolher demais ao realizar a pesquisa e substituição.
  • Para outros modelos que dependem do seu modelo por meio de chaves estrangeiras, os nomes das colunas de chave estrangeira das outras tabelas serão derivados do nome do modelo original. Portanto, você também desejará fazer algumas chamadas rename_column nesses modelos dependentes. Por exemplo, tive que renomear a coluna 'merchant_id' para 'business_id' em várias tabelas de junção (para o relacionamento has_and_belongs_to_many) e outras tabelas dependentes (para relacionamentos has_one e has_many normais). Caso contrário, eu teria terminado com colunas como 'business_stat.merchant_id' apontando para 'business.id'. Aqui está uma boa resposta sobre como renomear colunas.
  • Ao grepping, lembre-se de procurar versões singular, plural, maiúscula, minúscula e até MAIÚSCULAS (que podem ocorrer nos comentários) de suas seqüências de caracteres.
  • É melhor procurar primeiro versões plurais, depois singulares. Dessa forma, se você tiver um plural irregular - como no exemplo dos comerciantes :: empresas -, poderá corrigir todos os plurais irregulares. Caso contrário, você poderá acabar com, por exemplo, 'negócios' (3s) como um estado intermediário, resultando em ainda mais pesquisa e substituição.
  • Não substitua cegamente todas as ocorrências. Se os nomes dos seus modelos colidirem com termos de programação comuns, com valores em outros modelos ou com conteúdo textual em suas visualizações, você pode acabar ficando muito ansioso. No meu exemplo, eu queria alterar o nome do modelo para 'Negócios', mas ainda assim me referi a eles como 'comerciantes' no conteúdo da minha interface do usuário. Eu também tinha um papel de 'comerciante' para meus usuários no CanCan - foi a confusão entre o papel de comerciante e o modelo de comerciante que me levou a renomear o modelo em primeiro lugar.
armchairdj
fonte
26

Você também precisa substituir seus índices:

class RenameOldTableToNewTable< ActiveRecord:Migration
  def self.up
    remove_index :old_table_name, :column_name
    rename_table :old_table_name, :new_table_name
    add_index :new_table_name, :column_name
  end 

  def self.down
    remove_index :new_table_name, :column_name
    rename_table :new_table_name, :old_table_name
    add_index :old_table_name, :column_name
  end
end

E renomeie seus arquivos etc, manualmente, como outras respostas aqui descrevem.

Veja: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

Certifique-se de poder reverter e avançar depois de escrever essa migração. Pode ser complicado se você errar algo e ficar preso a uma migração que tenta efetuar algo que não existe mais. Melhor lixeira para todo o banco de dados e inicie novamente se você não puder reverter. Portanto, esteja ciente de que pode ser necessário fazer o backup de algo.

Além disso: verifique schema_db em busca de nomes de colunas relevantes em outras tabelas definidas por um has_ ​​ou pertence_ a ou algo assim. Você provavelmente precisará editá-los também.

E, finalmente, fazer isso sem um conjunto de testes de regressão seria maluco.

Rimian
fonte
11
Quanto às migrações do rails 4.0.0.beta1, não é necessário atualizar os índices manualmente. O AR o atualiza por si só.
freemanoid 5/05
1

Você pode executar este comando: rails g migration rename_ {old_table_name} para {new_table_name}

depois de editar o arquivo e adicionar esse código na alteração de método

rename_table: {old_table_name},: {new_table_name}

Mouhamadou Bamba Mboup
fonte