How to do save_or_update with ActiveRecords?

Hi,

I am trying to save return values from the Twitter API, so for example
I have created a model for DirectMessages and Users.

A direct message from Twitter contains a sender and recipient as
nested hashes.

I want to save these objects using the id from Twitter, too.

I convert the hash to models like this:

def convert_direct_message_hash_to_model(dm)
dm[“sender”] = User.new(dm[“sender”]){|sender| sender.id = dm
[“sender”][“id”]}
dm[“recipient”] = User.new(dm[“recipient”]) {|recipient| recipient.id
= dm[“recipient”][“id”]}
DirectMessage.new(dm) {|r| r.id = dm[“id”]}
end

then, if I try dm.save! with a self-sent message (so recipient =
sender), I get an SQL error, because user id should be unique. It
seems in this case ActiveRecord attempts to save the objects with an
INSERT statement.

Is there a way to make it update the record if the object already
exists in the db, and otherwise create it?

Also other comments to my approach are welcome, as I am fairly new to
Rails.

Thanks!

Björn

I get the error

On Oct 6, 11:46 pm, Bjoern [email protected] wrote:

then, if I try dm.save! with a self-sent message (so recipient =
sender), I get an SQL error, because user id should be unique. It
seems in this case ActiveRecord attempts to save the objects with an
INSERT statement.

Is there a way to make it update the record if the object already
exists in the db, and otherwise create it?

If that’s what you want then you should attempt to load the
appropriate object first, create a new one if you can’t find one and
then save (see also the dynamic finders -

)

Fred

Is there a way to make it update the record if the object already
exists in the db, and otherwise create it?

If that’s what you want then you should attempt to load the
appropriate object first, create a new one if you can’t find one and
then save (see also the dynamic finders -ActiveRecord::Base
)

Difficult, since the association seems to be saved automatically. I
guess I have to switch that off somehow, then. No other way available?

I’m not quite sure what you’re saying. Instead of doing User.new, try
to find an appropriate User record first.

I’d like to avoid that, to keep the part of the code clean from
database access. I create a DirectMessage with two associated Users
and then only call DirectMessage.save

I suppose I could check all the Users before doing the save, but it
would create a lot of clutter (compared to one line of executing
save). I was hoping there would be a more elegant way.

The API docs for save sound as if they would create or update, so
maybe the question is how do they decide what is new and what needs
updating.

On Oct 7, 1:47 am, Bjoern [email protected] wrote:

guess I have to switch that off somehow, then. No other way available?
I’m not quite sure what you’re saying. Instead of doing User.new, try
to find an appropriate User record first.

Fred

On Oct 7, 11:52 am, Frederick C. [email protected]
wrote:

If you do User.new you will always get a new object that AR will then
try to insert.

Any other options?

Sounds like you would also get an error whenever you handle a message
to / from a user you have already handled a message from.

True - so far I only tested it from unit tests, so I guess there was
nothing else in the db.

On Oct 7, 10:22 am, Bjoern [email protected] wrote:

The API docs for save sound as if they would create or update, so
maybe the question is how do they decide what is new and what needs
updating.

If you do User.new you will always get a new object that AR will then
try to insert.

Sounds like you would also get an error whenever you handle a message
to / from a user you have already handled a message from.

Fred

On Oct 7, 2:42 pm, Bjoern [email protected] wrote:

On Oct 7, 11:52 am, Frederick C. [email protected]
wrote:

If you do User.new you will always get a new object that AR will then
try to insert.

Any other options?

I think you just need to bite the bullet and find the record first.
having a neat one liner is one thing but only if it actually works.
You could hack around and fool activerecord into thinking the record
isn’t new even though you’ve just called User.new but you’d probably
just be storing up trouble for later and increasing the chances that
your code breaks with a later version of rails.

Fred