Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Ruby
Tree: ac0a2bf3a2

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib/centro/tracktor
tasks
test
.gitignore
MIT-LICENSE
README.rdoc
Rakefile
init.rb
install.rb

README.rdoc

Tracktor

Tracktor is a Rails plugin that eases audit logging of actors (creator and updater) for any class that descends from ActiveRecord::Base. The goal is to seamlessly log the actors without needing to explicitly mention them when writing your application code. This is accomplished by storing the current actor in a thread-local variable for the duration of a particular HTTP request (note that this means that Tracktor will not work with multi-threaded application servers).

Any time you create or update a record within the context of a request, an ActiveRecord::Observer takes over and sets the creator and updater automatically. In other words:

# before - app/controllers/books_controller.rb
def create
  @book = Book.create(params[:book].merge(:creator => current_user, :updater => current_user))
end

# after - app/controllers/books_controller.rb
def create
  @book = Book.create(params[:book])
end

The simplest setup for Tracktor is as follows:

# app/models/book.rb (repeat with every model class for which you'd like automatic actor tracking)
class Book < ActiveRecord::Base
  track_actors
end

# db/migrate/001_create_books.rb
class CreateBooks < ActiveRecord::Migration
  def self.up
    create_table :books do |t|
      t.actors
    end
  end
end

# app/controllers/application.rb
class ApplicationController < ActionController::Base
  enable_actor_tracking
end

Models

Tracktor adds an ActiveRecord::Base.track_actors method that sets up automatic actor tracking for the class. By default, Tracktor assumes that the actor's class name is “User”; if this is not the case, you can specify the class name like so:

class Book < ActiveRecord::Base
  track_actors :class_name => "Member"
end

You can also specify a default actor, which will be used if there is no current actor set:

class Book < ActiveRecord::Base
  track_actors :default => lambda { User.find_by_id(0) }
end

Specifying track_actors will allow you to reference the creator and updater associations from the object being tracked:

book = Book.create!(:name => "Survivor")
puts book.creator

Migrations

Tracktor adds an ActiveRecord::Migration#actors method that creates two integer columns: creator_id and updater_id. These columns reference the row ids of the actors that created or updated the book.

By default, these columns have not-null constraints (:null => false), but this may be overridden if desired. No foreign keys are created; if you care about that sort of thing, make sure you include it in your migration.

Controllers

Tracktor adds an ActionController::Base.enable_actor_tracking method, which should be added to application.rb after any before_filter or other code that is responsible for logging users in. This method wraps the request such that the current actor is available to an Observer that watches for record creation or updating.

By default, the enable_actor_tracking method will try to grab the actor by calling the current_user method; this can be overridden like so:

enable_actor_tracking :from => :logged_in_user

Testing

Tracktor hearts Test-Driven Development. In fact, Tracktor hearts TDD so much that it adds a Test::Unit::TestCase.test_actor_tracking_for method that can be used like so:

class BookTest < Test::Unit::TestCase
  test_actor_tracking_for :book
end

This will create and run the following tests:

  • test_creator_association

  • test_updater_association

  • test_creator_should_be_set_to_current_before_validation_on_create

  • test_updater_should_be_set_to_current_before_validation

  • test_creator_should_default_when_current_is_not_set

  • test_updater_should_default_when_current_is_not_set

Any other tests you'd like to write (to test custom class names, etc.) are on you.

If you're using Shoulda by ThoughtBot, you can instead use the Shoulda macro, like so:

class BookTest < Test::Unit::TestCase
  context "an existing book"
    setup { @book = Book.create! }
    should_track_actors_for :book
  end
end

This will create the appropriate shoulds.

Etc.

There are times when it is necessary to create/update objects that normally track actors when you are outside of the context of an HTTP request (or inside one without a logged in user). For this, Tracktor includes the as_actor method, which can be used like so:

as_actor(User.find_by_id(0)) do
  Book.create!(:name => "Choke")
end

This can be especially useful when writing tests, command-line scripts, rake tasks, etc. Tracktor adds validations to creator_id and updater_id, so an error that states “Updated by can't be blank” will often point to the fact that you are operating outside the context of an HTTP request, and need to use as_actor.

Copyright © 2008 Centro, released under the MIT license. Authored by:

Something went wrong with that request. Please try again.