9

この方法でレコードを更新する必要があるのか​​ 、それとも何かが欠けているのかわかりません。

5 つの列 (タイムスタンプと ID を含まない) を持つテーブルがあり、そのうち 3 つは個別で、2 つは更新されます。私が検索または作成する 3 つの異なる要素は、room_id、date、および source です。他の 2 つは価格と利用可能なスポットです (これらは時間ごと、日ごとなどに変化します)。

私の質問は、最初にレコードを検索または作成してから、価格とスポットを更新 (または作成) する必要があるか、それともすべてを一度に行うことができるかということです。私が現在行っている2つの方法を見ることができますが、実際に私が期待していることを行っているかどうかはわかりません.

また、このように find_and_create_by を実行することの欠点はありますか?

ありがとう

  private

  def self.parse_data(params,data)
    data.beds.each do |bed|
      room = Room.find_or_create_room(bed.title, params[:id])

      #find clones somehow
      #puts bed.nights.first.price
      bed.nights.each_with_index do |night,index|
        available = Available.find_or_create_by_room_id_and_bookdate_and_source(
          :room_id => room.id, 
          :bookdate => (params[:date].to_date)+index, 
          :source => data.class.to_s#,
          #:price => night.price
        )
        #available.price = night.price
        #available.spots = night.spots
        #available.save
      end

    end
4

3 に答える 3

24

実際には、ハッキングなしの方法があります。find_or_create_by の代わりに、find_or_initialize_by を使用して、タップで更新された属性を設定できます

Available.find_or_initialize_by_room_id_and_bookdate_and_source(
  room.id, 
  (params[:date].to_date)+index, 
  data.class.to_s#
).tap do |a|
  a.price = night.price
  a.spots = night.spots
end.save!

最初はこれは雑然としているように見えますが、まさにあなたが要求したことを実行しています。レコードを見つけ、見つからない場合はインスタンス化し、属性を更新します。これは「find_and_update_or_create_by」と呼ばれる可能性がありますが、幸いなことに誰もそれを行いませんでした。;) この助けを願っています。

于 2012-07-10T07:29:08.507 に答える
15

ここに 2 つのアプローチがあります。

まずAvailable、必要な正確な方法で拡張でき

def self.find_or_create_by_room_id_and_bookdate_and_source(room_id, bookdate, source, &block)
  obj = self.find_by_room_id_and_bookdate_and_source( room_id, bookdate, source ) || self.new(:room_id => room_id, :bookdate => bookdate, :source => source)
  yield obj
  obj.save
end

利用方法

Available.find_or_create_by_room_id_and_bookdate_and_source(room.id, (params[:date].to_date)+index, data.class.to_s) do |c|
  c.price = night.price
  c.spots = night.spots
end

これは厄介です。したがって、より柔軟にするために、魔法を使用するためupdate_or_create_by...のメソッドを作成できます。ActiveRecordmethod_missing

class ActiveRecord::Base
  def self.method_missing(method_id, *args, &block)
    method_name = method_id.to_s
    if method_name =~ /^update_or_create_by_(.+)$/
      update_or_create($1, *args, &block)
    else
      super
    end
  end
  def self.update_or_create(search, *args, &block)
    parameters = search.split("_and_")
    params = Hash[ parameters.zip(args) ]
    obj = where(params).first || self.new(params)
    yield obj
    obj.save
    obj
  end
end

これで、次のように使用できます。

Available.update_or_create_by_id_and_source(20, "my_source") do |a|
  a.whatever = "coooool"
end
于 2011-04-07T11:10:26.117 に答える