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@example.com"
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@example.com"
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@example.com"
user.save
end