Forum: Ruby on Rails Updating only changed columns in ActiveRecord

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 candlerb (Guest)
on 2007-05-01 12:29
(Received via mailing list)
Does anyone know of a way to get ActiveRecord to update only the
columns which have changed? For example, consider a table foos with
columns x,y,z. If I do

    f = Foo.find(123)
    f.update_attributes(:x => 99)

then I want AR to generate

    UPDATE foos SET x=99 WHERE id=123

rather than what it currently does:

    UPDATE foos SET x=99, y=2, z=3 WHERE id=123

(assuming y=2 and z=3 were the values read in by Foo.find)

Why do I want this? Well, I have tables which are updated
asynchronously due to external events, as well as by the user looking
at the record in Rails. Both the frontend and the event-handling
backend are using ActiveRecord. There are some fields which are
updated by the operator, and others which are updated by the backend.
But using ActiveRecord, there's a race condition between reading a row
and writing it back out again, which means that changes made by the
other party may be lost.

I searched for a plugin at
http://agilewebdevelopment.com/plugins/search?search=update
but couldn't find anything relevant.

So, the options I can think of are:

(1) Bypass ActiveRecord's 'save' and 'update' methods entirely

    f = Foo.find(123)
    ... compare f with params, determine that only 'x' has changed
    Foo.update_all(['x=?',params[:foo][:x]], ['id=?',123])

But this has to be done consistently everywhere. I guess I can write
my own version of update_attributes which does this.

(2) Read each record twice:

    f1 = Foo.find(123)
    ... compare f1 with params, determine that only 'x' has changed
    f2 = Foo.find(123, :select => 'x')
    f2.update_attributes(params[:foo])

This seems like unnecessary overhead.

I had a quick look through the code path for 'update_attributes' but
it seems to be intimately bound to 'save', and 'save' seems to have no
concept of which attributes have changed.

Thanks for any suggestions.

Regards,

Brian.
This topic is locked and can not be replied to.