Adicionando: default => true ao booleano na coluna Rails existente

160

Eu já vi algumas perguntas (ou seja, essa ) aqui no SO sobre como adicionar um valor booleano padrão a uma coluna existente. Então tentei a change_columnsugestão, mas não devo estar fazendo certo.

Eu tentei:

$ change_column :profiles, :show_attribute, :boolean, :default => true

Que retorna -bash: change_column: command not found

Eu então corri:

$ rails g change_column :profiles, :show_attribute, :boolean, :default => true

...e

$ rails change_column :profiles, :show_attribute, :boolean, :default => true

Em seguida rake db:migrate, correu , mas o valor para :show_attributepermaneceu nil. Na pergunta mencionada acima, no PostgreSQL, você precisa atualizá-lo manualmente. Como estou usando o PostgreSQL, adicionei o seguinte na minha create_profilesmigração:

t.boolean :show_attribute, :default => true

Alguém pode me dizer o que estou fazendo de errado aqui?

tvalent2
fonte

Respostas:

314

change_columné um método de ActiveRecord::Migration, então você não pode chamá-lo assim no console.

Se você deseja adicionar um valor padrão para esta coluna, crie uma nova migração:

rails g migration add_default_value_to_show_attribute

Em seguida, na migração criada:

# That's the more generic way to change a column
def up
  change_column :profiles, :show_attribute, :boolean, default: true
end

def down
  change_column :profiles, :show_attribute, :boolean, default: nil
end

OU uma opção mais específica:

def up
    change_column_default :profiles, :show_attribute, true
end

def down
    change_column_default :profiles, :show_attribute, nil
end

Então corra rake db:migrate.

Não mudará nada para os registros já criados. Para fazer isso, você teria que criar um rake taskou apenas entrar rails consolee atualizar todos os registros (o que eu não recomendaria na produção).

Quando você adicionou t.boolean :show_attribute, :default => trueà create_profilesmigração, espera-se que ela não tenha feito nada. Somente migrações que ainda não foram executadas são executadas. Se você iniciou com um novo banco de dados, ele definiria o padrão como true.

Robin
fonte
2
Essa chamada change_column deve estar no upmétodo da migração, que é uma nova classe que será gerada em db / migrate /. (O downmétodo deve ser escrito para desfazer o que upfaz.) Faça essa alteração, então rake db:migrate.
Rkb
Ahh, isso faz mais sentido rkb. Obrigado!
tvalent2
que não estava funcionando para mim até que eu escrevi def self.upedef self.down
Kamil Szot
Você provavelmente está usando uma versão mais antiga dos trilhos. Eu acho que essa sintaxe existe desde 3.1.
Robin
E no Rails 5, você deixa o _attribute para que ele diga showou seja qual for o nome da coluna.
labirinto
95

Como variação da resposta aceita, você também pode usar o change_column_defaultmétodo em suas migrações:

def up
  change_column_default :profiles, :show_attribute, true
end

def down
  change_column_default :profiles, :show_attribute, nil
end

Documentos da API do Rails

Sebastiaan Pouyet
fonte
1
Isso garante que você não vai acidentalmente alterar qualquer uma das outras propriedades da coluna
Brian Low
1
E no Rails 5 você deixa de fora o atributo, por isso deve dizer showou qualquer que seja o nome da coluna.
labirinto
1
@ labyrinth O que você quer dizer? show_attribute é o nome da coluna, acho que o rails 5 não tem nada a ver com isso, certo?
Robin
34

Não tenho certeza de quando isso foi escrito, mas atualmente para adicionar ou remover um padrão de uma coluna em uma migração, você pode usar o seguinte:

change_column_null :products, :name, false

Trilhos 5:

change_column_default :products, :approved, from: true, to: false

http://edgeguides.rubyonrails.org/active_record_migrations.html#changing-columns

Trilhos 4.2:

change_column_default :products, :approved, false

http://guides.rubyonrails.org/v4.2/active_record_migrations.html#changing-columns

Essa é uma maneira pura de evitar procurar nas suas migrações ou esquema as especificações da coluna.

fbelanger
fonte
Cuidado, é da documentação do Rails 5. A versão do Rails 4.2 não aceita hash, mas exatamente o novo padrão como terceiro parâmetro. Guides.rubyonrails.org/v4.2/…
Clamoris
Sobre Trilhos 5, fazendo as duas coisas parece ser a maneira mais correta, por exemplo, null: falsee default: :somethingbasicamente
Dorian
1

Além disso, conforme o documento:

o padrão não pode ser especificado via linha de comando

https://guides.rubyonrails.org/active_record_migrations.html

Portanto, não há gerador de trilhos pronto para uso. Conforme especificado pelas respostas acima, você deve preencher manualmente seu arquivo de migração com o change_column_defaultmétodo

Você pode criar seu próprio gerador: https://guides.rubyonrails.org/generators.html

Margotte
fonte
1

Se você acabou de fazer uma migração, poderá reverter e fazer sua migração novamente.

Para reverter, você pode executar quantas etapas desejar:

rake db:rollback STEP=1

Ou, se você estiver usando o Rails 5.2 ou mais recente:

rails db:rollback STEP=1

Em seguida, você pode simplesmente fazer a migração novamente:

def change
  add_column :profiles, :show_attribute, :boolean, default: true
end

Não se esqueça de rake db:migratee se você estiver usando herokuheroku run rake db:migrate

BM
fonte
0
change_column :things, :price_1, :integer, default: 123, null: false

Parece ser a melhor maneira de adicionar um padrão a uma coluna existente que ainda não o possui null: false.

De outra forma:

change_column :things, :price_1, :integer, default: 123

Algumas pesquisas que fiz sobre isso:

https://gist.github.com/Dorian/417b9a0e1a4e09a558c39345d50c8c3b

Dorian
fonte
0

Se você não deseja criar outro arquivo de migração para uma alteração pequena e recente - no Rails Console:

ActiveRecord::Migration.change_column :profiles, :show_attribute, :boolean, :default => true

Então saia e entre novamente no console do rails, para que as DB-Changes entrem em vigor. Então, se você fizer isso ...

Profile.new()

Você deve ver o valor padrão "show_attribute" como true.

Para registros existentes, se você deseja preservar as configurações "falsas" existentes e atualizar apenas os valores "nil" para seu novo padrão:

Profile.all.each{|profile| profile.update_attributes(:show_attribute => (profile.show_attribute == nil ? true : false))  }

Atualize a migração que criou esta tabela, para que futuras compilações do banco de dados o consigam desde o início. Execute também o mesmo processo em qualquer instância implantada do banco de dados.

Se você estiver usando o método "new db migration", poderá atualizar os valores nulos existentes nessa migração.

JosephK
fonte