# Finding out updated fields

**URL:** <https://www.ruby-forum.com/t/finding-out-updated-fields/58021>\
**Category:** Rails\
**Created:** [April 17, 2006, 8:19pm UTC](https://www.ruby-forum.com/t/finding-out-updated-fields/58021 "2006-04-17T20:19:06Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![lantis](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/4da419/32.png) [@lantis](https://www.ruby-forum.com/u/lantis)\
**Post date:** [April 17, 2006, 8:19pm UTC](https://www.ruby-forum.com/t/finding-out-updated-fields/58021/1 "2006-04-17T20:19:06Z")

</div>

Hi,

When we update a record via an update form, is there an easy way to find  
out the fields that have been changed. If the update is successful, i  
want to display:  
The following fields have been changed:  
field-name = new-value  
…

Thanks,

Lantis.

---

<div class="post-metadata">

**Author:** ![lantis](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/4da419/32.png) [@lantis](https://www.ruby-forum.com/u/lantis)\
**Post date:** [April 18, 2006, 6:34am UTC](https://www.ruby-forum.com/t/finding-out-updated-fields/58021/2 "2006-04-18T06:34:52Z")

</div>

There is a recipe for doing this called “Keeping Track of Who Did What”  
in the book “Rails Recipes”  
([http://pragmaticprogrammer.com/titles/fr\_rr/](http://pragmaticprogrammer.com/titles/fr_rr/)).

-Jeremy

---

<div class="post-metadata">

**Author:** ![lantis](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/4da419/32.png) [@lantis](https://www.ruby-forum.com/u/lantis)\
**Post date:** [April 18, 2006, 5:02pm UTC](https://www.ruby-forum.com/t/finding-out-updated-fields/58021/3 "2006-04-18T17:02:48Z")

</div>

It’s not really what i want. That recipe shows how to keep track of  
user’s activity. What i want is to find out what was changed in the edit  
operation (the fields of the record & the new values).

Thanks anyway,

Lantis.

---

<div class="post-metadata">

**Author:** ![lantis](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/4da419/32.png) [@lantis](https://www.ruby-forum.com/u/lantis)\
**Post date:** [April 18, 2006, 8:43pm UTC](https://www.ruby-forum.com/t/finding-out-updated-fields/58021/4 "2006-04-18T20:43:06Z")

</div>

I am also interested in a solution to this problem since I have a form  
with over 100’s text fields and I dont want to load teh DB with updating  
all fields every time only one is updated…

My current idea would be to associate each text field with a hiden field  
containing the old\_value of the field. And when you do the update, you  
only update the records for which old\_field != new\_field.

But still, I dont find this solution very elegant. Since rails know the  
value of all fields (that is how it is able to auto-populate them), it  
should be aware of changes to any of these fields by comparing the  
params hash with the hash in memory.

Anyone can comment on this? I am just guessing…

---

<div class="post-metadata">

**Author:** ![lantis](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/4da419/32.png) [@lantis](https://www.ruby-forum.com/u/lantis)\
**Post date:** [April 18, 2006, 10:05pm UTC](https://www.ruby-forum.com/t/finding-out-updated-fields/58021/5 "2006-04-18T22:05:17Z")

</div>

Hello,

Lantis :

> It’s not really what i want. That recipe shows how to keep track of  
> user’s activity. What i want is to find out what was changed in the edit  
> operation (the fields of the record & the new .

Alain :

> […] Since rails know the value of all fields (that is how it  
> is able to auto-populate them), it should be aware of changes  
> to any of these fields by comparing the  
> params hash with the hash in memory.

Yes, I think that’s the way we should do it, if Rails doesn’t do it,  
let’s do it instead !

Assuming a Person model, here a typical scaffolded code…

def edit  
@person = Person.find(params[:id])  
end

def update  
@person = Person.find(params[:id])  
if @person.update\_attributes(params[:person])  
flash[:notice] = ‘Person was successfully updated.’  
redirect\_to :action =\> ‘show’, :id =\> @person  
else  
render :action =\> ‘edit’  
end  
end

So, the idea is to take the params[:person] hash and remove  
the not-changing key/value pairs.

def update  
@person = Person.find(params[:id])

```
attr = @person.attributes
new_attr = params[:person]
new_attr.delete_if { |k,v| attr.has_key?(k) && attr[k] == v }

# => updated fields in new_attr Hash
# if we wanna display it, use a @new_attr variable.

if @person.update_attributes(new_attr)
  flash[:notice] = 'Person was successfully updated.'
  redirect_to :action => 'show', :id => @person
else
  render :action => 'edit'
end

```

end

No tested though, but it should do the trick.

So if it works, you can add a method to AR::B like that :

def update\_only\_changed\_attributes(attrs)  
attrs.delete\_if do|key,value|  
has\_attribute?(key) && self[key] == value  
end  
update\_attributes(attrs)  
end

Not tested… again 🙂

In the debugging process of this method, i’m wondering if we  
have to check for the primary key, to remove it from the hash or not.  
And other issues i haven’t suspected… (do i have to stringify the keys  
?)

```
 -- Jean-FranÃ§ois.
```

---

<div class="post-metadata">

**Author:** ![lantis](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/4da419/32.png) [@lantis](https://www.ruby-forum.com/u/lantis)\
**Post date:** [April 18, 2006, 10:33pm UTC](https://www.ruby-forum.com/t/finding-out-updated-fields/58021/6 "2006-04-18T22:33:08Z")

</div>

Alain wrote:

> should be aware of changes to any of these fields by comparing the  
> params hash with the hash in memory.
> 
> Anyone can comment on this? I am just guessing…

Yes, I think it’d be useful for Active Record to track which  
attributes in a model have changed, both allowing the user to  
identify changed fields, and restricting DB updates to only those  
changed fields.

I actually wrote a mod to implement this, but I don’t think I’ve  
fully tested it. It adds a @changed\_attributes hash to a model.

What held me up was also implementing a @changed\_association hash  
which allowed AR to not only automatically save the new records  
in an object’s descended associates, but also any changed attribute  
in those descendants. This would simplify controller code.

Here’s the code to get the flavour of what is required. Changed  
lines marked with ‘N’.

* * *

module ActiveRecord  
class Base  
def initialize(attributes = nil)  
@attributes = attributes\_from\_column\_definition  
N @changed\_attributes = {}  
@new\_record = true  
ensure\_proper\_type  
self.attributes = attributes unless attributes.nil?  
yield self if block\_given?  
end

```
 def write_attribute(attr_name, value)
   attr_name = attr_name.to_s
   if (column = column_for_attribute(attr_name)) && column.number?
     new_value = convert_number_column_value(value)

```

N if new\_value != @attributes[attr\_name]  
N @changed\_attributes[attr\_name] = true  
N @attributes[attr\_name] = new\_value  
end  
else  
@attributes[attr\_name] = value  
end  
end

private  
N def attributes\_with\_quotes(include\_primary\_key = true, only\_changed  
= false)  
attributes.inject({}) do |quoted, (name, value)|  
if column = column\_for\_attribute(name)  
N unless !include\_primary\_key && column.primary || only\_changed  
&& @changed\_attributes[name]  
quoted[name] = quote(value, column)  
end  
end  
quoted  
end  
end

```
 def update

```

N quoted\_attributes = attributes\_with\_quotes(false,true)  
connection.update(  
"UPDATE #{self.class.table\_name} " +  
N "SET #{quoted\_comma\_pair\_list(connection, quoted\_attributes)} "  
+  
“WHERE #{self.class.primary\_key} = #{quote(id)}”,  
“#{self.class.name} Update”  
N ) unless quoted\_attributes.empty?

```
   return true
 end

```

## end end

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