Rails 6
O Rails 6 adicionou um método upsert
e upsert_all
que oferece essa funcionalidade.
Model.upsert(column_name: value)
[upsert] Não instancia nenhum modelo nem aciona callbacks ou validações do Active Record.
Trilhos 5, 4 e 3
Não se você estiver procurando por um tipo de instrução "upsert" (onde o banco de dados executa uma atualização ou uma instrução de inserção na mesma operação). Fora da caixa, Rails e ActiveRecord não têm esse recurso. Você pode usar a gema upsert , no entanto.
Caso contrário, você pode usar: find_or_initialize_by
ou find_or_create_by
, que oferece funcionalidade semelhante, embora ao custo de uma ocorrência adicional no banco de dados, o que, na maioria dos casos, dificilmente é um problema. Portanto, a menos que você tenha sérias preocupações de desempenho, eu não usaria a gema.
Por exemplo, se nenhum usuário for encontrado com o nome "Roger", uma nova instância do usuário é instanciada com seu name
conjunto para "Roger".
user = User.where(name: "Roger").first_or_initialize
user.email = "[email protected]"
user.save
Alternativamente, você pode usar find_or_initialize_by
.
user = User.find_or_initialize_by(name: "Roger")
No Rails 3.
user = User.find_or_initialize_by_name("Roger")
user.email = "[email protected]"
user.save
Você pode usar um bloco, mas o bloco só é executado se o registro for novo .
User.where(name: "Roger").first_or_initialize do |user|
# this won't run if a user with name "Roger" is found
user.save
end
User.find_or_initialize_by(name: "Roger") do |user|
# this also won't run if a user with name "Roger" is found
user.save
end
Se você quiser usar um bloco independentemente da persistência do registro, use tap
no resultado:
User.where(name: "Roger").first_or_initialize.tap do |user|
user.email = "[email protected]"
user.save
end
find_or_initialize_by
efind_or_create_by
aceitam um bloqueio. Achei que você quisesse dizer que, quer o registro exista ou não, um bloco será passado com o objeto do registro como argumento, a fim de fazer a atualização.No Rails 4 você pode adicionar a um modelo específico:
e usar como
Ou se você preferir adicionar esses métodos a todos os modelos colocados em um inicializador:
fonte
assign_or_new
retornará a primeira linha da tabela se ela existir e então essa linha será atualizada? Parece estar fazendo isso por mim.User.where(email: "[email protected]").first
retornará nulo se não for encontrado. Certifique-se de ter umawhere
lunetaupdated_at
não será tocado porqueassign_attributes
é usadoAdicione isto ao seu modelo:
Com isso, você pode:
fonte
A magia que você estava procurando foi adicionada em
Rails 6
Agora você pode fazer o upsert (atualizar ou inserir). Para uso de registro único:Para vários registros, use upsert_all :
Nota :
fonte
Pergunta antiga, mas jogando minha solução no ringue para ser completa. Eu precisava disso quando precisava de um achado específico, mas uma criação diferente, se ela não existir.
fonte
Você pode fazer isso em uma declaração como esta:
fonte
A sequência gem adiciona um método update_or_create que parece fazer o que você está procurando.
fonte