This feature was released in Rails v2.3.3
There are often times when you want an update made to one object to be reflected up the object graph as an update of an associated parent object. For instance, if a new comment is created on an article, you may very well want to mark the article as being updated. With the new touch feature of ActiveRecord, this is a whole lot easier. Using our previous example, here’s is how it works:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Article < ActiveRecord::Base has_many :comments end class Comment < ActiveRecord::Base # Make create/update/deletes of a comment mark its # parent article as updated belongs_to :article, :touch => true end # Adding a new comment marks the article as being updated article.updated_at #=> "Mon Apr 20 07:42:53 -0400 2009" article.comments.create(:body => "New comment") article.updated_at #=> "Mon Apr 20 07:43:27 -0400 2009" # Same for updates/deletes article.comments.first.destroy article.updated_at #=> "Mon Apr 20 07:45:23 -0400 2009" |
This is a great way to keep tightly coupled domain models in-sync without resorting to a potential maze of callback logic.
Also, if you have a timestamp field named something other than the standard updated_at or updated_on you can explicitly specify that field as the value to the :touch option and it will get marked instead:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Article < ActiveRecord::Base has_many :comments validates_presence_of :last_updated_at # non-standard end class Comment < ActiveRecord::Base belongs_to :article, :touch => :last_updated_at end # Adding a new comment marks the article as being updated article.last_updated_at #=> "Mon Apr 20 07:42:53 -0400 2009" article.comments.create(:body => "New comment") article.last_updated_at #=> "Mon Apr 20 07:43:27 -0400 2009" |
Also, somewhat conveniently, you can invoke touch directly on a model to update its timestamp outside any association callbacks:
1 2 3 |
article.updated_at #=> "Mon Apr 20 07:42:53 -0400 2009" article.touch article.updated_at #=> "Mon Apr 20 07:43:27 -0400 2009" |
So, touch away (in a non-creepy kind of way)!
tags: ruby, rubyonrails

Wow that sounds like a great feature :)
I can see this making passive cache invalidation much easier ;)
If you are working with legacy systems and have to have touch point to a column name you might want to look at http://github.com/adkron/legacy_woes
If you are using legacy woes you can make update_at(on), :created_at(on) point to the non-standard naming convention, and then if you switch to the standard you don’t have to change all your touches.
I’m running into some rather annoying issues with optimistic locking… specifically when destroying associated records that touch the parent record. For example…
We have two models, User and Comments. Users have many comments. User has optimistic locking enabled. Comments are set to touch their user. In the user model we have…
before_destroy {|u| u.comments.destroy_all}
Now if we have multiple comments, StaleObjectErrors are thrown because each destroy touches the user, and thus increments it’s lock. Simplest solution would be to give us something like destroy_without_touching and maybe destroy_all_without_touching. I don’t know, but there might be other places where *_without_touching methods may be needed.
For now I just turn off locking for a tiny spec of time while the destroy_all is run. Oh and thanks for this new feature, it rocks. It removed some horribly complex callbacks from our app… callbacks that were causing lots of these blasted stale errors. I’m very happy that the only ones I have to deal with now are on destroy, since no one uses that feature anyway!
Touching isn’t actually in 2.3, right? Is the article just incorrectly labeled?
Hey JL, I believe you’re right – this update is a post-2.3 feature. Not sure what made me think it was in 2.3 in the first place. My bad!
No problem Ryan…wish it was in 2.3 though.