Rails: Adicionando um índice após adicionar coluna


119

Suponha que eu criei uma tabela tableem um aplicativo Rails. Algum tempo depois, adiciono uma coluna executando:

rails generate migration AddUser_idColumnToTable user_id:string. 

Então percebo que preciso adicionar user_idcomo um índice. Eu sei sobre o add_indexmétodo, mas onde deve ser chamado esse método? Devo executar uma migração (em caso afirmativo, qual?) E, em seguida, adicionar manualmente esse método?

Respostas:


235

Você pode executar outra migração, apenas para o índice:

class AddIndexToTable < ActiveRecord::Migration
  def change
    add_index :table, :user_id
  end
end

4
Então, eu simplesmente executo no meu console: rails generate migration AddIndexToTable?
user1611830

3
Sim, você pode fazer isso, mas terá que editar essa migração depois para refletir o código acima.
Jaap Haagmans

É: a tabela deveria ser plural?
tumba

1
@tomb Usei o exemplo da pergunta original. :tableé o nome tabela real, assim, no caso de uma userstabela, você iria substituir :userspor :table.
Jaap Haagmans

65

Se você precisar criar um user_id, seria razoável supor que você está referenciando uma tabela de usuário. Nesse caso, a migração será:

rails generate migration AddUserRefToProducts user:references

Este comando irá gerar a seguinte migração:

class AddUserRefToProducts < ActiveRecord::Migration
  def change
    add_reference :user, :product, index: true
  end
end

Depois de executar, rake db:migrateuma user_idcoluna e um índice serão adicionados à productstabela.

Caso você precise apenas adicionar um índice a uma coluna existente, por exemplo, namede uma usertabela, a seguinte técnica pode ser útil:

rails generate migration AddIndexToUsers name:string:index irá gerar a seguinte migração:

class AddIndexToUsers < ActiveRecord::Migration
  def change
    add_column :users, :name, :string
    add_index :users, :name
  end
end

Excluir add_column linha e execute a migração.

No caso descrito, você poderia ter emitido o rails generate migration AddIndexIdToTable index_id:integer:indexcomando e, em seguida, excluir a add_columnlinha da migração gerada. Mas eu prefiro recomendar desfazer a migração inicial e adicionar referência em vez disso:

rails generate migration RemoveUserIdFromProducts user_id:integer
rails generate migration AddUserRefToProducts user:references

Obrigado Vadym pela resposta completa. Uma última pergunta: por que você recomendaria desfazer a migração inicial? Existe algum problema de desempenho relacionado à adição de índice posteriormente?
Flavio Wuensche

2
Para @fwuensche: não há penalidade de desempenho para adicionar índice posteriormente. A lógica do domínio será menos clara, no entanto. Por exemplo, no caso de você decidir quebrar / abstrair / etc a associação mais tarde, você precisará lidar com duas migrações separadas, que realmente deveriam ter sido uma única ...
Vadym Tyemirov

6
AVISO: Observe que index: true só funciona em uma migração create_table. A migração será executada, mas nenhum índice será criado. Consulte makandracards.com/makandra/…
rmcsharry de

9

Adicione a migração gerada após criar a coluna a seguir (exemplo)

add_index :photographers, :email, :unique => true

você quer dizer algo assim: def self.up add_column ... end add_index ...?
user1611830

5

Para referências, você pode ligar

rails generate migration AddUserIdColumnToTable user:references

Se no futuro você precisar adicionar um índice geral, você pode lançar este

rails g migration AddOrdinationNumberToTable ordination_number:integer:index

Gerar código:

class AddOrdinationNumberToTable < ActiveRecord::Migration
  def change
   add_column :tables, :ordination_number, :integer
   add_index :tables, :ordination_number, unique: true
  end
end

0

Você pode usar isso, basta pensar que Job é o nome do modelo ao qual você está adicionando o índice cader_id :

class AddCaderIdToJob < ActiveRecord::Migration[5.2]
  def change
    change_table :jobs do |t|
      t.integer :cader_id
      t.index :cader_id
    end
  end
end
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.