acts_as_current
This library extends ActiveRecord classes so they can carry a reference to the instance defined as current for the given request.
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
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.
Helpful Links
-
Repository: github.com/coroutine/acts_as_current
-
Authors: coroutine.com
Installation & Generators
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
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. :-)
License
Copyright © 2010 Coroutine LLC, released under the MIT license.
acts_as_current was inspired by sentient_user, copyright © 2009 bokmann, also released under the MIT license.