Much like how Timestamping callbacks are set up by default for columns named @created_at@/@created_on@ and @updated_at@/@updated_on@, (See http://rails.rubyonrails.com/classes/ActiveRecord/Timestamp.html) this will automaticaly populate @created_by@ and @updated_by@ fields with the user who created/updated items.

Also see ExtendingActiveRecordExample for more examples on how to extend ActiveRecord to your needs.

h2. The Code

Place this in @/lib/usermonitor.rb@

<pre><code>module ActiveRecord

  module UserMonitor

    def self.included(base)

      base.class_eval do
        alias_method :create_without_user, :create
        alias_method :create, :create_with_user

        alias_method :update_without_user, :update
        alias_method :update, :update_with_user
      end
    end

    def create_with_user
        user = user_model.current_user
        self[:created_by] = user if respond_to?(:created_by) && created_by.nil?
        self[:updated_by] = user if respond_to?(:updated_by)
        create_without_user
    end

    def update_with_user
        user = user_model.current_user
        self[:updated_by] = user if respond_to?(:updated_by)
        update_without_user
    end

    def created_by
      begin
        user_model.find(self[:created_by])
      rescue ActiveRecord::RecordNotFound
        nil
      end
    end

    def created_by=(user)
      self[:created_by] = user.id
    end

    def updated_by
      begin
        user_model.find(self[:updated_by])
      rescue ActiveRecord::RecordNotFound
        nil
      end
    end

    def updated_by=(user)
      self[:updated_by] = user.id
    end

  end

  class Base

    @@default_user_model = :users
    cattr_accessor :user_model_name

    def self.user_model_name
      if @@user_model.nil?
        @@default_user_model
      else
        @@user_model
      end
    end

    def self.relates_to_user_in(model)
      self.user_model_name = model
    end

    def user_model
      Object.const_get(self.user_model_name.to_s.singularize.humanize)
    end
  end
end
</code></pre>

Then add the following to the bottom of @/config/environment.rb@

<pre><code>require 'usermonitor'
ActiveRecord::Base.class_eval do
  include ActiveRecord::UserMonitor
end
</code></pre>

Now if you add @created_by@ or @updated_by@ to your database tables, you will be able to access the user who created/updated the objects by calling @object.created_by@ and @object.updated_by@ respectively. Likewise you can set the user by assiging a user object to either one.

This defaults to assuming you have a user model called User, which can be overriden by calling @relates_to_user_in@ in your model like so:

<pre><code>
class WebPage < ActiveRecord::Base
  relates_to_user_in :monkeys
end
</code></pre>

The user model must contain "current_user" that references the currently logged in user.

category:Howto
