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 protected]"
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 protected]"
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 protected]"
user.save
end
find_or_initialize_by
etfind_or_create_by
acceptent un blocage. Je pensais que vous vouliez dire que, que l'enregistrement existe ou non, un bloc sera transmis avec l'objet d'enregistrement comme argument, afin de faire la mise à jour.Dans Rails 4, vous pouvez ajouter à un modèle spécifique:
et utilisez-le comme
Ou si vous préférez ajouter ces méthodes à tous les modèles mis dans un initialiseur:
la source
assign_or_new
retournera pas la première ligne de la table si elle existe, puis cette ligne sera mise à jour? Il semble faire cela pour moi.User.where(email: "[email protected]").first
renverra nul s'il n'est pas trouvé. Assurez-vous d'avoir unewhere
lunetteupdated_at
cela ne sera pas touché car ilassign_attributes
est utiliséAjoutez ceci à votre modèle:
Avec cela, vous pouvez:
la source
La magie que vous recherchiez a été ajoutée dans
Rails 6
Vous pouvez désormais insérer (mise à jour ou insertion). Pour un seul enregistrement:Pour plusieurs enregistrements, utilisez upsert_all :
Remarque :
la source
Ancienne question mais jetant ma solution dans le ring pour l'exhaustivité. J'en avais besoin quand j'avais besoin d'une découverte spécifique mais d'une création différente si elle n'existe pas.
la source
Vous pouvez le faire en une seule déclaration comme celle-ci:
la source
Le gem suite ajoute une méthode update_or_create qui semble faire ce que vous recherchez.
la source