Categories
Programming

I want my @current_user in my model: A Lesson in Abstraction

This method was adapted from this blog post.

So, you are creating a thing (record) or maybe you are updating it. You’ve added created_by and updated_by fields to your model, and you’ve made these integers with the intention of them both being foreign keys to the Users model.

Maybe you’ve even setup a belongs_to relationsion to your User model like so:

class Thing
 belongs_to :creator, :foreign_key => ‘created_by’, :class_name => ‘User’
 belongs_to :updater, :foreign_key => ‘updated_by’, :class_name => ‘User’
end

(this way you can refer to thing.creator and thing.updater)

Now, you want to actually set these fields when you create a record or update a record. Problem is, your current_user method is a controller method, and isn’t available in your model layer.

Well, this IS a problem. There are many ways to hack it- but here’s the best approach. I’m going to do this backwards for clarity.

1. Make user_info.rb in your models directory

module UserInfo
 def current_user
  Thread.current[:user]
 end

 def self.current_user=(user)
  Thread.current[:user] = user
 end
end

2. Now you need the TrackUsers class, which is real simple. Make another file in your models class called “track_users.rb”. Notice that we’re mixing in the UserInfo module we just created.

module TrackUsers
 # mix me into the OBSERVER for any class you want to set the created_by, updated_by fields
 
 include UserInfo
 
 def before_update(record)
  record.updated_by = current_user.id if current_user
 end
 
 def before_create(record)
  record.created_by = current_user.id if current_user
 end
end

3. Make an observer class for Thing (you can make this in your models folder). Call the file “thing_observer.rb”. Notice that all this basically does is mix in the TrackUsers module.

class ThingObserver < ActiveRecord::Observer
 include TrackUsers
end

4. Setup an Observer for your (this goes inside the Rails::Initializer.run do |config| block)

 config.active_record.observers = [
  :thing_observer
  ]

5. In your ApplicationController add this:

 before_filter :set_user

 # … some more of your code …

protected
 def set_user
  if current_user
   UserInfo.current_user = current_user
  end
 end

Leave a Reply

OR LOG IN WITH




Your email address will not be published. Required fields are marked *