Create or update -

Hi everyone,

I’m looking for a shortcut to finding and updating or creating record
depending on the results of the find.

So, is there a shorter way to do it than this?

@stuff = Stuff.find_by_foo_and_bar(“yay”,“hooray”)
if @stuff: Stuff.update(@stuff.id, {:foo => “boo”, :bar => “hoo”})
else Stuff.create({:foo => “boo”, :bar => “hoo”})
end

By the way, I can’t believe that I want to do this in less than 3.1
lines of code. Rails is making me lazy. Anyway, anyone who can suggest
something nicer & shorter gets my gratitude and an imaginary gold star.

thanks!

Dan

dan wrote:

I’m looking for a shortcut to finding and updating or creating record
depending on the results of the find.

So, is there a shorter way to do it than this?

@stuff = Stuff.find_by_foo_and_bar(“yay”,“hooray”)
if @stuff: Stuff.update(@stuff.id, {:foo => “boo”, :bar => “hoo”})
else Stuff.create({:foo => “boo”, :bar => “hoo”})
end

@stuff = Stuff.find_by_foo_and_bar(“yay”,“hooray”) || Stuff.new
@stuff.update_attributes(:foo => “boo”, :bar => “hoo”)


We develop, watch us RoR, in numbers too big to ignore.

Mark Reginald J. wrote:

dan wrote:

I’m looking for a shortcut to finding and updating or creating record
depending on the results of the find.

So, is there a shorter way to do it than this?

@stuff = Stuff.find_by_foo_and_bar(“yay”,“hooray”)
if @stuff: Stuff.update(@stuff.id, {:foo => “boo”, :bar => “hoo”})
else Stuff.create({:foo => “boo”, :bar => “hoo”})
end

@stuff = Stuff.find_by_foo_and_bar(“yay”,“hooray”) || Stuff.new
@stuff.update_attributes(:foo => “boo”, :bar => “hoo”)


We develop, watch us RoR, in numbers too big to ignore.

I think a term for this is called “Upsert” - so does rails or any
existing plugin/helper already have the ability to do it. If not, then
maybe a generic helper method would be in order. Stuff.upsert(…) I
think this could be somewhat difficult to implement generically without
knowing the fields that determine the uniqueness of a record (user
keys).

Michael

On 04/08/06, Michael M. [email protected] wrote:

I think a term for this is called “Upsert” - so does rails or any
existing plugin/helper already have the ability to do it. If not, then
maybe a generic helper method would be in order. Stuff.upsert(…) I
think this could be somewhat difficult to implement generically without
knowing the fields that determine the uniqueness of a record (user
keys).

The primary_key is guaranteed to be unique within a table. By default,
this
is called “id”, if not, I’m certain there’s a way to look it up. What
more
do you need to know, pseudocode implementation below, in a class
inheriting
from ActiveRecord::Base?
def upsert(id, fields)
Record = self.find(:first, :id=> id)
newRecord = Record.copy # deep copy method, consensus on Google seems
to
be that
# there’s no built-in copy
function
in Ruby
fields.each { |x|
newRecord.x= fields[x]
}
newRecord.id = self.find(:all).length + 1
newRecord.save
end

Hasan D. wrote:

On 04/08/06, Michael M. [email protected] wrote:

I think a term for this is called “Upsert” - so does rails or any
existing plugin/helper already have the ability to do it. If not, then
maybe a generic helper method would be in order. Stuff.upsert(…) I
think this could be somewhat difficult to implement generically without
knowing the fields that determine the uniqueness of a record (user
keys).

The primary_key is guaranteed to be unique within a table. By default,
this
is called “id”, if not, I’m certain there’s a way to look it up. What
more
do you need to know, pseudocode implementation below, in a class
inheriting
from ActiveRecord::Base?
def upsert(id, fields)
Record = self.find(:first, :id=> id)
newRecord = Record.copy # deep copy method, consensus on Google seems
to
be that
# there’s no built-in copy
function
in Ruby
fields.each { |x|
newRecord.x= fields[x]
}
newRecord.id = self.find(:all).length + 1
newRecord.save
end

I think you are assuming he knows the id of the record. I believe if
that were the case, then he would just do an update.

An upsert is something you can do when you DO NOT know if it is an
insert or an update. However, an ID field is rarely known in a true
upsert. Take a contact for example. A user tries to add John D. with
phone 555-444-3333. Then, another user tries to add another John D.
with phone 333-444-5555. Is this a change in phone number or a new John
Doe contact? The way you determine this is by defining the user keys
that determine the uniqueness of a record. If you define this user key
to be First Name, Last Name only then this John D. example would be an
update. If, however, you define the user key to be First Name, Last
Name and Phone Number then this John D. is an Insert.

Does that make sense? You would need to know what fields define the
uniqueness of a record in order to accomplish this task - thus making it
difficult to make generic.

Regards,

Michael

The unique’nes is identified by the ‘unique’ index on the table. Primary
key
has a “unique” index on it. So in your scenario if the user has defined
a
compound index on First Name + Last Name + Phone then it will throw an
unique index error.

Many DB supports the insert/update syntax now-a-days:

In MYSQL it would be something like:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;

More information on:
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Guess Oracle also has such feature.

One idea of generic interface could be, if the underlying DB supports
“upsert” delegate do it otherwise wrap a “insert/catch duplicate/update”
statement.

_Hari

codeslush wrote:

newRecord = Record.copy # deep copy method, consensus on Google seems
end
that determine the uniqueness of a record. If you define this user key
Michael


Posted via http://www.ruby-forum.com/.


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails


View this message in context:
http://www.nabble.com/create-or-update---tf2044153.html#a5860818
Sent from the RubyOnRails Users forum at Nabble.com.

On 8/3/06, dan [email protected] wrote:

else Stuff.create({:foo => “boo”, :bar => “hoo”})
end

I can name that tune in one note:
@stuff = Stuff.find_or_create_by_foo_and_bar(“yay”,“hooray”)

This assumes that you don’t have any validations which would block the
creation of a record with only these attributes.