Rails: updating an association through nested attributes does not touch the owner

I was a little surprised to discover that when you update an association through nested attributes, it won’t touch the parent record.  It makes sense when you consider that Rails is optimizing by not writing records that have not changed, but if were using updated_at on the model for caching you may be surprised.

For instance:

With these models:

This code will not change updated at on the post record:

As shown in the log:

The fix is very simple. Just touch the post record from the comment if you need updated_at to change on posts.

And now our post is updated:

Of course there are other ways to do this…

The code for this is on github.

Caching user records when using Authlogic

Today, I ran across another form of this issue with Authlogic. In short, every request in a Rails application using Authlogic with a User model that includes a last_request_at column will cause the updated_at column to change. This can break caching that is based on the last time a user was updated.

last_request_at is one of Authlogic’s magic columns and is useful if you want to track users that might be logged in. However, by including this column, every controller request will touch the user record and change updated_at.

If you add last_request_at to your User model, you’ll start seeing this in your application logs:

UPDATE “users” SET “last_request_at” = ‘2014-03-12 20:59:48.314863’, “updated_at” = ‘2014-03-12 20:59:48.320481’

However, if you’ve added e-tags to a controller based on the updated_at timestamp, you’ll now have broken your cache control.  For instance, this will no longer work:

To fix caching based on the User’s updated_at timestamp with Authlogic, you can add your own timestamp and maintain it whenever the User record changes. Here is what I came up with:

  1. Add a new column, user_updated_at, to the user model
  2. Whenever a relevant column changes on user, set user_updated_at to Time.now
  3. Change the cache control to be based on user_updated_at instead of updated_at
Here is what that looks like in the User model:


And in the controller:


This made my controller request caching work as expected.  How would you handle this?