How do I update an existing record if the one saved has the same key?

MySQL has a very nice option for the operator INSERT

, which is especially useful for columnless join tables id

. It inserts a record, but instead of throwing an error if its key collides with an existing one, that record is updated. Here's an example:

INSERT INTO table (key1,key2,data) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE data=3;

      

How can I achieve the same result with Active Record? The resulting code will look like this:

class Model < ActiveRecord::Base
  belongs_to :key1
  belongs_to :key2
end

record = Model.new
record.key1 = key1
record.key2 = key2
record.data = 'new data'
record.WHAT?    #Inserts or updates `data` for the existing record

      

+2


a source to share


4 answers


J's answer is the correct idea, but you probably want to go with find_or_initialize_by to avoid saving multiple objects. For instance.

record = Model.find_or_initialize_by_key1_and_key2 new
record.data = 'new data'
record.save

      



By the sounds of this, you also want to validate the correctness of checking that the model also does not allow duplicate joins:

class Model < ActiveRecord::Base
  belongs_to :key1
  belongs_to :key2
  validates_uniqueness_of :key1, :scope => :key2
end

      

+3


a source


You can do the following:

record = Model.find_or_create_by_key1_and_key2(:key1 => key1, :key2 => key2)
record.update_attribute(:data, "new data")

      



EDIT

The zaius idea looks better, you should use find_or_initialize_by

to avoid multiple saves as he said:]

+2


a source


You might want to take a look at composite primary keys . This is a plugin for ActiveRecord.

+1


a source


Firstly, a MySQL specific solution, as far as I know this syntax does not work with any other SQL servers. Usually referred to as Upsert in discussions.

I would include a new method called save_or_update

and then if the save fails, with a duplicate key exception, load and update_params

.

0


a source







All Articles