acts_as_current

This library extends ActiveRecord classes so they can carry a reference to the instance defined as current for the given request.

Usage

acts_as_current can be applied to any model, but it’s most common use case is storing the authenticated user on the corresponding User model. Doing so allows other models and observers to access information about the user who made the request. This is particularly useful for auditing, versioning, etc.

Here’s how you’d set up the user example.

First, extend the User model.

class User < ActiveRecord::Base
    acts_as_current
end

Then, tell your application controller to set the current user before all requests. (The controller method can obviously be anything you want. Here, we use :current_user because that’s our convention at Coroutine.)

class ApplicationController < ActionController::Base

    before_filter { |controller| User.current = controller.send(:current_user) }

    def current_user
        # return user or nil
    end
end

Finally, in your observer, you can retrieve the value of current_user by using the accessor mixed into the model class.

class AuditObserver < ActiveRecord::Observer
    observe :account, :balance

    def after_update(record)
        AuditTrail.new({ :record => record, :action => :update, :whodunnit => User.current })
    end
end

Simple Controller Recipe

He’s an example of how you might set a current instance on a User class via a current_user method, using a before filter in the application controller.

before_filter { |controller| User.current = controller.send(:current_user) }

Why Doesn’t the Library Handle the Controller Logic For Me?

Primarily, because we think ActiveRecord extensions have no business altering controller logic. Doing so couples aspects of your application that Rails is going out of its way to separate.

But also because the before_filter syntax is already configurable and extremely expressive. Writing the before filter is no harder than writing a module include statement, but the former tells a code maintainer considerably more information than the latter.

In summary, suck it up and write the controller code yourself. :-)

Design Notes

acts_as_current uses the hash Thread.current to store the current value for each class extended by the library. Many consider this technique a hack, but for now, it is the only thread safe way to store such data. By coding the technique as a model extension, acts_as_current abstracts reads and writes against Thread.current, greatly reducing the likelihood of conflicts and errors.

We think the real benefits outweigh the perceived risks.

Installation (Rails 3)

Install me from RubyGems.org by adding a gem dependency to your Gemfile. Bundler does the rest.

gem “acts_as_current” $ bundle install

Installation (Rails 2)

Install me from RubyGems.org and add a gem dependency in your configuration file.

$ sudo gem install acts_as_current

Or install me as a plugin.

$ script/plugin install git://github.com/coroutine/acts_as_current.git

Gemroll

Other gems by Coroutine include:

License

Copyright © 2010 Coroutine LLC.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

acts_as_current was inspired by sentient_user, copyright © 2009 bokmann, also released under the MIT license.