Rails 6
Rails 6 a ajouté une méthode upsert
et upsert_all
qui offre cette fonctionnalité.
Model.upsert(column_name: value)
[upsert] Il n'instancie aucun modèle et ne déclenche pas de rappel ou de validation Active Record.
Rails 5, 4 et 3
Pas si vous recherchez un type d'instruction "upsert" (où la base de données exécute une mise à jour ou une instruction d'insertion dans la même opération). Hors de la boîte, Rails et ActiveRecord n'ont pas une telle fonctionnalité. Vous pouvez cependant utiliser la gemme upsert .
Sinon, vous pouvez utiliser: find_or_initialize_by
ou find_or_create_by
, qui offrent des fonctionnalités similaires, mais au prix d'un accès supplémentaire à la base de données, ce qui, dans la plupart des cas, n'est pas du tout un problème. Donc, à moins que vous ayez de sérieux problèmes de performances, je n'utiliserais pas la gemme.
Par exemple, si aucun utilisateur n'est trouvé avec le nom "Roger", une nouvelle instance d'utilisateur est instanciée avec son name
réglage sur "Roger".
user = User.where(name: "Roger").first_or_initialize
user.email = "email@example.com"
user.save
Vous pouvez également utiliser find_or_initialize_by
.
user = User.find_or_initialize_by(name: "Roger")
Dans les rails 3.
user = User.find_or_initialize_by_name("Roger")
user.email = "email@example.com"
user.save
Vous pouvez utiliser un bloc, mais le bloc ne s'exécute que si l'enregistrement est nouveau .
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
Si vous souhaitez utiliser un bloc quelle que soit la persistance de l'enregistrement, utilisez tap
sur le résultat:
User.where(name: "Roger").first_or_initialize.tap do |user|
user.email = "email@example.com"
user.save
end