October 17, 2008
Older: Suggest a Topic Today
Newer: Giving Mailers, Observers and Sweepers Their Own Space
Who Done What? a.k.a. User Stamping
Something I do in every app I create is add creator_id and updater_id to nearly every model. As created_at and updated_at are known as timestamping, I refer to my creator and updater attributes as “user stamping.” The annoying part is in every controller I had to assign those attributes to the currently logged in user. This isn’t a big deal but I’m lazy so I started to look for solutions.
Thread.current
The first thing that popped into my head was Thread.current
. Thread.current
is basically a hash that allows you to assign thread-safe key value pairs for the current thread. My thought, based on some research, was to wrap Thread.current[:myapp_user_id]
with User.current
so I could just use User.current
in any active record model. Only problem is that smelled a little bit and I figured would be frowned upon by the community as you really shouldn’t access request stuff in your models like that. You can read more about threads and Thread.current if you want.
Solution: Sweeper
I brainstormed a bit with Brandon Keepers and he suggested a few things. Eventually, we decided on a sweeper as they have access to controllers which would have access to the current user. Tada! User Stamp, the plugin, was born. I whipped it together last night (< 50 LOC), added a few specs, and put it up on github this morning.
Installation
Installation is uber predictable.
script/plugin install git://github.com/jnunemaker/user_stamp.git
Once plugin is installed and user_stamp call with list of models to track in application.rb.
class ApplicationController < ActionController::Base
user_stamp Post, Asset, Job
end
If you actually want to access this stuff through associations and show it in your app you could do something like this:
class Post < ActiveRecord::Base
belongs_to :creator, :class_name => 'User'
belongs_to :updater, :class_name => 'User'
end
Then, say in a view, you could do the following:
<h1><%=h @post.name %></h1>
<div><%= @post.content %></div>
<p>Posted by <%=h @post.creator.name %></p>
Let me know what you think in the comments. Bugs can be reported in lighthouse.
11 Comments
Oct 17, 2008
Umm. Just so you know. From 2006?
http://agilewebdevelopment.com/plugins/userstamp
Oct 17, 2008
@court3nay – Yeah I used that back in the day. Seemed like a lot of code for something simple. Also, that uses Thread.current which isn’t bad per say but I think my solution is a little more simple.
Oct 17, 2008
For those using Merb with DataMapper, I’ve knocked up something similar.
http://github.com/rlivsey/dm-userstamp/tree/master
Oct 18, 2008
great plugin!
im using make_resourceful, so i did this in after :update,:create
but sweepers seem even cleaner, ill giv it a try in the next days
just an idea: will the plugin crash when my model does not have an updater_id ?
Oct 18, 2008
@grosser – No, it won’t fail. It checks if the model responds to creator_id and updater_id before assigning each attribute. It also checks if your controller responds to current_user, so it won’t fail if you are missing that either.
Oct 18, 2008
But, there are another thread, which manages another threads and give them priority?
Oct 19, 2008
@Mark – Not sure I understand what you are asking/stating.
Oct 24, 2008
Hey, useful plugin. I’ve built on it and implemented a full audit-trail of user actions on the models being watched by User Stamp.
Auditing models with User Stamp
Oct 27, 2008
Good plugin. I’ll like it even better when I get it working! ;-)
Question from rails noob, which controller needs the current_user method? How is it defined?
Oct 27, 2008
@Chris – Check out restful_authentication. It works out of the box with that. If you aren’t using that, current_user should be defined in application.rb.
Nov 14, 2008
We built something similar for our rails app: http://github.com/centro/tracktor/tree/master
I like our model a little better because you annotate each model with whether or not it’s tracked in the model’s class, instead of in a controller class. But hey— at the end of the day, there’s plenty of ways to slice this particular cheesecake!
Sorry, comments are closed for this article to ease the burden of pruning spam.