Update_attribute send updates every field, why?


#1

Hi,

If you do model.update_attribute(“fname”, “John”) the every field is
updated, it generates a big update statement like:

update persons set fname=x, lname=y, email=z, whatever=blah,
and_stuff=stuff where id=1

I would think it would just generate:
update persons set fname=‘John’ where id=1

Anybody know why AR acts this way?

Jeroen


#2

Jeroen H. wrote:

Anybody know why AR acts this way?

I think that’s just the Rails does it. Records are always
saved in their entirety.

I’ve found the following simple Active Record extentions to be
helpful in cutting out some useless database activity:

class ActiveRecord::Base
def changed(attrs)
return false if attrs.nil?
self.class.content_columns.each { |c| return true if self[c] !=
attrs[c] }
return false
end

def update_attributes_if_changed(attrs)
changed(attrs) ? update_attributes(attrs) : true
end

def update_attribute_if_changed(name, value)
self[name] != value ? update_attribute(name, value) : true
end
end


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


#3

Mark Reginald J. wrote:

I would think it would just generate:

changed(attrs) ? update_attributes(attrs) : true

end

def update_attribute_if_changed(name, value)
self[name] != value ? update_attribute(name, value) : true
end
end

This doesn’t address my original problem though, right? I mean in the
end you still call update_attribute which generates the full update
SQL, not just for one field. Or am I missing something here…

Jeroen


#4

Jeroen H. wrote:

This doesn’t address my original problem though, right? I mean in the
end you still call update_attribute which generates the full update
SQL, not just for one field. Or am I missing something here…

Yes, as I wrote, unless you do custom SQL, Rails always saves entire
records.
The code I gave was just a way to cut out unnecessary saves in certain
circumstances.

I’m not sure whether entire records are saved to simplify the Rails
code,
or because of some tricky issues that would arise if attributes could
be updated individually. At the least you’d probably have to add a
dirty
bit to each record, or to each attribute in each record.


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


#5

I too am observing this. Can anyone throw some light on this behaviour?


#6

From ActiveRecord::Base:

 def update_attribute(name, value)
    send(name.to_s + '=', value)
    save
  end
 def save
    raise ActiveRecord::ReadOnlyRecord if readonly?
    create_or_update
  end

The call to ‘create_or_update’ will trigger either object#create or
object#update, each of which contains the SQL code that persists the
attributes in the object. You could probably override
update_attribute, and have it call a new method
‘create_or_update_lone_attribute’ instead of ‘save’. Doesnt look like
that would break anything.

On the other hand, why? Unless you have some huge binary columns, the
db will update n columns in a record just about as quick as a single
column.

cheers
Gerret