Jonas Grau Jonas Grau - 4 months ago 20
Ruby Question

Best way to find_or_create_by_id but update the attributes if the record is found

I'm looking for a clean way to create a record with a set of attributes if the record does not exist and - if the record do exist - to update its attributes. I love the syntax of the block in the find_or_create_by_id call. Here's my code:

@categories = Highrise::DealCategory.find(:all)

@categories.each do |category|
puts "Category: #{category.name}"

Category.find_or_create_by_id(category.id) do |c|
c.name = category.name
end
end


The problem here is that if the record exists but the name has changed, it is not being updated.

Looking for a clean solution to this problem...

Answer

You can write your own method:

class ActiveRecord::Base
  def self.find_by_id_or_create(id, &block)
    obj = self.find_by_id( id ) || self.new
    yield obj
    obj.save
  end
end

usage

 Category.find_by_id_or_create(10) do |c|
   c.name = "My new name"
 end

Of course, in this way you should extend method missing method and implement this method in the same way as others find_by_something methods. But for being short this will be enough.