8

自家製のRESTAPIを使用して新しいデータを挿入するRails3.2.8アプリケーションに取り組んでいます。挿入ロジックはすべてのエンドポイントで一般的であり、Model.saveを呼び出すだけで済みます。

モデルタイプの1つについて、最初に既存のレコードが存在するかどうかを確認し、存在する場合は、挿入ではなく更新します。コードでコントローラーレベルでの対話が許可されている場合、これはfind_or_create_byを使用することで簡単になりますが、(私が思うに)唯一のオプションは、モデルのsaveメソッドをオーバーライドするか、before_saveコールバックを使用することです。

モデル内でsaveまたはupdate_attributesを呼び出すと、(明らかな理由で)無限ループが発生するため、これを機能させる方法を見つけるのに苦労しています。

before_saveを利用する方法、または属性xとyを持つレコードが存在するかどうかを最初に確認できるようにsaveをオーバーライドする方法はありますか?存在する場合は、そのレコードを取得して更新を実行します。それ以外の場合は、標準のActiveRecord保存を使用しますか?

これが現在Activityモデル内にある私のコードですが、無限ループの問題のために機能しません:

def save
  a = UserActivity.find_or_initialize_by_user_id_and_activity_id(user_id: user_id,     activity_id: activity_id)
  a.update_attributes start_at: start_at, end_at: end_at.....
end
4

1 に答える 1

10

あなたは方法を必要としているようですfind_or_create_by_*

ループを回避するには、これをsaveメソッドに配置するのではなく、次の2つの場所のいずれかに配置する必要があります。

オプション1:コントローラーレベル

このインスタンスをインスタンス化するコントローラーではUserActivity、代わりに次のように記述します。

a = UserActivity.find_or_create_by_user_id_and_activity_id(user_id: user_id, activity_id: activity_id)
a.update_attributes start_at: start_at, end_at: end_at.....

オプション2:クラスメソッド

上記のコードを複数のコントローラーに追加している場合は、次のクラスで新しいクラスメソッドを定義することをお勧めしますUserActivity

class UserActivity
  def self.create_or_update_from_attrs(user_id, activity_id, start_at, end_at...)
    a = UserActivity.find_or_create_by_user_id_and_activity_id(user_id: user_id,     activity_id: activity_id)
    a.update_attributes start_at: start_at, end_at: end_at.....
  end
end

そして、コントローラーでは、明らかに:

UserActivity.create_or_update_from_attrs(...)

保存を上書きする

もちろん、saveメソッドをオーバーライドすることもできますが、これはRailsの機能(find_or_create_by...)を複製するため、DRY違反し、後で遭遇した他の状況と競合するときに自分の足を撃つ可能性があるため、使用をお勧めしませんこれの:

編集:無限ループを回避するために更新

class UserActivity
  def save
    # If this is new record, check for existing and update that instead:
    if new_record? && a = UserActivity.where(user_id: user_id, activity_id: activity_id).first
      a.update_attributes start_at: start_at, end_at: end_at ...
      return true # just to comply with Rails conventions          
    else
      # just call super to save this record
      super
    end
  end
end
于 2012-11-05T20:11:00.373 に答える