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?

Testing ASP.NET MVC Filters

Testing controllers in ASP.NET MVC is straight forward.  However, testing action filters applied to controllers or actions requires jumping through a few hoops.  Since filters are applied by the framework, calling the action directly means no filters are executed.  Thus, you write two tests: one for the filter and one that the controller is decorated with the filter.

Background
Testing controller actions is pretty simple:

  1. Instantiate the controller
  2. Invoke the action
  3. Test the result.

For instance:

However, you can’t use this same pattern for testing filters applied to actions or controllers. Filters are invoked by the ASP.NET MVC framework.  When you invoke an action directly on the controller, it does not execute the filters for the controller or the action.
For example, the following test case fails:


As mentioned above, to test filters you need to test two things:

  1. The filter is applied to you controller or action
  2. The filter code
Testing Filter Application
Using reflection, you can get get all the filters applied to an action or controller.  The following snippet shows how you could test that a filter is applied to an action. 
This code:

  1. Gets the action method from the controller
  2. Finds an attribute for the filter
  3. Checks that the method has a filter

Testing that controllers have filters applied is similar.  See the download at the end of this post for sample code.


Testing Filters

Testing filters is more complicated that testing controllers.  We need to:

  1. Mock up a filter context
  2. Create the filter
  3. Invoke the appropriate filter action
  4. Test the filter result

The following, using Moq, shows how you can perform these steps in a test:

Further reading: