1. ホーム
  2. ruby-on-rails

[解決済み] Railsは魔法を作ったり、更新したりするのか?

2022-11-05 12:53:46

質問

というクラスがあります。 CachedObject というクラスがあり、キーでインデックス化された一般的なシリアル化されたオブジェクトを格納しています。このクラスには create_or_update メソッドを実装したい。オブジェクトが見つかったらそれを更新し、そうでなければ新しいものを作成します。

Railsでこれを行う方法はありますか?それとも自分でメソッドを書かなければなりませんか?

どのように解決するのですか?

Rails 6

Rails 6では upsert upsert_all メソッドがあり、この機能を提供します。

Model.upsert(column_name: value)

[upsert] モデルをインスタンス化することも、Active Recordコールバックや検証を起動することもありません。

Rails 5、4、および3

upsert"(データベースが同じ操作でupdateまたはinsert文を実行する)タイプの文を探している場合は違います。RailsとActiveRecordには、そのような機能はありません。そのため upsert gemを使うことができます。

でなければ、使えるのは find_or_initialize_by または find_or_create_by などがあり、これらは似たような機能を提供しますが、追加のデータベースヒットの代償として、ほとんどの場合、ほとんど問題にはなりません。そのため、深刻なパフォーマンス上の懸念がない限り、私はこの gem を使用しません。

例えば、Roger" という名前のユーザが見つからなかった場合、新しいユーザインスタンスが name を"Roger"に設定します。

user = User.where(name: "Roger").first_or_initialize
user.email = "[email protected]"
user.save

あるいは find_or_initialize_by .

user = User.find_or_initialize_by(name: "Roger")

Rails 3では。

user = User.find_or_initialize_by_name("Roger")
user.email = "[email protected]"
user.save

ブロックを使っても良いですが の場合のみ、ブロックが実行され、レコードが新しい .

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

レコードの永続性に関係なくブロックを使いたい場合は tap を結果上で使用します。

User.where(name: "Roger").first_or_initialize.tap do |user|
  user.email = "[email protected]"
  user.save
end