Adicione um valor padrão a uma coluna através de uma migração

276

Como adiciono um valor padrão a uma coluna que já existe por meio de uma migração?

Toda a documentação que posso encontrar mostra como fazê-lo se a coluna ainda não existir, mas neste caso existe.

Jon
fonte

Respostas:

352

Aqui está como você deve fazê-lo:

change_column :users, :admin, :boolean, :default => false

Porém, alguns bancos de dados, como o PostgreSQL, não atualizarão o campo para as linhas criadas anteriormente, portanto, atualize o campo manualmente também na migração.

Maurício Linhares
fonte
14
Se você precisar de migrações reversíveis, coloque-o em um upbloco e não em um changebloco. Você pode deixar o downbloco vazio. Não reverterá a tabela para a condição original, mas a migração pode ser revertida.
IAmNaN
1
Isso manterá os dados intactos?
Marco Prins
2
No PostgreSQL, sim, não sei o que acontecerá em outros bancos de dados.
Maurício Linhares
1
O que você quer dizer quando diz "certifique-se de atualizar o campo manualmente na migração"? Como é que alguém faz isso?
David Argyle Thacker
7
Eu tentei no PostgreSQL e atualizou os campos criados anteriormente.
Aboozar Rajabi
190
change_column_default :employees, :foreign, false
Gazza
fonte
1
@DenisLins Eu concordei com você, então fiz algumas pesquisas para descobrir por que não pode ser, e acontece que existe uma possibilidade de que um adaptador de banco de dados específico não o suporte, pois é implementado nesse nível. A resposta aceita ainda é a aposta mais segura até ser implementada no modelo abstrato. apidock.com/rails/ActiveRecord/ConnectionAdapters/…
natchiketa
5
Além disso, é preciso especificar um from:e to:se você quer que ele seja reversível :)
radubogdan
5
Usando frome tofoi adicionado no Rails 5+ neste commit: github.com/rails/rails/pull/20018/files
Joshua Pinter
115

Para Rails 4+ , usechange_column_default

def change
  change_column_default :table, :column, value
end
csi
fonte
1
Isso é ótimo, especialmente se você tiver uma migração que está adicionando uma coluna e configurando padrões para registros existentes. Por exemplo: def change `add_column: foos,: name, default:" algo para valores existentes "` `change_column_default: foos,: name, default:" "`end
user1491929
2
Essa migração tem um comportamento estranho. No seu exemplo, é irreversível. edgeguides.rubyonrails.org/active_record_migrations.html recomenda usá-lo desta maneira: change_column_default :products, :approved, from: true, to: false- mas também não funciona.
Ilya Krigouzov
não pode reverter usando isso?
Aldrien.h
Normalmente, sim, para quase qualquer cláusula "Change", uma vez que todos os estados anteriores são geralmente explícitos, como a presença de uma coluna, seu tipo, etc. A alteração pode ser revertida, como é mostrado lá se e somente se houver um padrão explícito válido anteriormente. Como é comum os padrões serem indefinidos, você pode ter um problema lá.
Elindor
48

Usar def changesignifica que você deve escrever migrações reversíveis. E change_columnnão é reversível. Você pode subir, mas não pode descer, poischange_column é irreversível.

Em vez disso, embora possa haver algumas linhas extras, você deve usar def up edef down

Portanto, se você tiver uma coluna sem valor padrão, faça isso para adicionar um valor padrão.

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: nil
end

Ou se você deseja alterar o valor padrão para uma coluna existente.

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: true
end
bfcoder
fonte
37

** Rails 4.X + **

No Rails 4, você não pode gerar uma migração para adicionar uma coluna a uma tabela com um valor padrão. As etapas a seguir adicionam uma nova coluna a uma tabela existente com o valor padrão true ou false.

1. Execute a migração da linha de comandos para adicionar a nova coluna

$ rails generate migration add_columnname_to_tablename columnname:boolean

O comando acima irá adicionar uma nova coluna na sua tabela.

2. Defina o novo valor da coluna como TRUE / FALSE editando o novo arquivo de migração criado.

class AddColumnnameToTablename < ActiveRecord::Migration
  def change
    add_column :table_name, :column_name, :boolean, default: false
  end
end

** 3 Para fazer as alterações na tabela do banco de dados do aplicativo, execute o seguinte comando no terminal **

$ rake db:migrate
Praveen George
fonte
Como isso é diferente dos trilhos 3+ ou 2+?
Ruby Racer
2
Alguém sabe se isso foi incorporado ao Rails 5?
Sambecker # 1/16
9

Executar:

rails generate migration add_column_to_table column:boolean

Irá gerar esta migração:

class AddColumnToTable < ActiveRecord::Migration
  def change
    add_column :table, :column, :boolean
  end
end

Defina o valor padrão adicionando: default => 1

add_column: table,: column,: boolean,: default => 1

Corre:

rake db: migrate

axeltaglia
fonte
2
Agora, o valor padrão de 1 não é exatamente um boolean;) Além disso, este exampe adiciona uma nova coluna, em vez de alterar a coluna existente, que é o que o OP queria atingir
radiospiel
@radiospiel Na verdade, 1 é um boolean também :)
kinduff
Você também precisará criar um registro na tabela de chaves estrangeiras com um ID 1 para que isso funcione, para evitar o Key is not present in table error.
Promise Preston
-50

Isto é o que você pode fazer:

class Profile < ActiveRecord::Base
  before_save :set_default_val

  def set_default_val
    self.send_updates = 'val' unless self.send_updates
  end
end

EDIT: ... mas, aparentemente, este é um erro de novato!

rookieRailer
fonte
É melhor se você definir o padrão no esquema vs como umbefore_save
rigelstpierre
6
Que sugestão terrível
svelandiag
concordou, é realmente terrível
Houcheng
3
ai, você tem muito calor para fazer algo no nível do modelo em vez do nível do banco de dados. -38 é uma pontuação lendária.
nurettin
1
que erro estreante ... ;-) #
webaholik 26/06