find_or_create_by在Rails 3和更新创建记录



我不确定我是否应该以这种方式更新记录,或者如果我错过了一些东西。

我有一个有5列(不包括时间戳和id)的表,其中3列是不同的,2列将被更新。我将通过room_id、date和source找到或创建3个不同的名称。另外两个是价格和可用位置(每小时、每天等变化)

我的问题是,我应该先找到或创建记录,然后更新(或创建)价格和现货,还是我可以一次完成所有操作?你可以看到我现在用的两种方法,我不确定它是否真的在做我所期望的。

另外,这样做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

实际上,有一种不需要黑客攻击的方法。您可以使用find_or_initialize_by来代替find_or_create_by,并使用tap

设置更新的属性
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",幸运的是没有人这样做。;)

有两种方法。

首先你可以用你需要的确切方法扩展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

这很尴尬。因此,为了更加灵活,您可以使用method_missing magic为ActiveRecord创建update_or_create_by...方法:

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

我认为最简单的方法是使用Ruby的tap方法,像这样:

def self.parse_data(params,data)
  data.beds.each do |bed|
    room = Room.find_or_create_room(bed.title, params[:id])
    bed.nights.each_with_index do |night,index|
      Available.find_or_initialize_by(room_id: room.id).tap do |available|
        available.bookdate = (params[:date].to_date) + index
        available.source = data.class.to_s
        available.price = night.price
        available.save
      end
    end
  end
end

find_or_initialize_by查找或初始化一条记录,然后返回它。然后我们进入它,进行更新并将其保存到数据库。

相关内容

  • 没有找到相关文章

最新更新