Cameron Yule

Auditing models with user_stamp

As part of a CMS I’m building I wanted the ability to audit user interaction with data, to prevent the situation where content is being created, deleted or edited with no record of who did what and when.

John Nunemaker recently released his User Stamp plug-in which stamps records with the ID of the users that created and last updated. The implementation is quite clever, as he’s managed to work around the usual hack of storing the current user ID in Thread.current to make it accessible to the model by using a Sweeper, as they have access to controllers (and hence the current_user method).

I’ve taken his code a bit further by creating a Log model which stores a polymorphic reference to the record affected, the event that occurred (e.g. ‘deleted’ or ‘updated’), the current user ID and the time it happened.

The Log model;

class Log < ActiveRecord::Base
 
  # Relationships
  belongs_to :user
  belongs_to :loggable, :polymorphic => :true
 
  # Validations
  validates_presence_of :loggable_type
  validates_presence_of :loggable_id
  validates_presence_of :action
  validates_presence_of :user
 
end

The migration;

class CreateLogs < ActiveRecord::Migration
  def self.up
    create_table :logs do |t|
      t.string :loggable_type
      t.integer :loggable_id
      t.string :action
      t.references :user
      t.timestamps
    end
    add_index :logs, :loggable_id
    add_index :logs, :user_id
  end
 
  def self.down
    drop_table :logs
  end
end

Additional callback methods added to UserStampSweeper;

  def after_create(record)
    add_log(record, 'created')    
  end
 
  def after_update(record)
    add_log(record, 'updated')    
  end
 
  def after_destroy(record)
    add_log(record, 'delete')    
  end
 
  private
  def add_log(record, action)
    Log.create(
      :loggable_type => record.class.to_s, 
      :loggable_id => record.id, 
      :action => action, 
      :user => current_user
    )
  end

Displaying the logs;

<% for log in @logs %>
  <tr>
    <td><%= link_to (h log.loggable.log_name), [:admin, log.loggable] %></td>
    <td><%= h log.loggable_type %></td>
    <td><%= h log.action %></td>
     <td><%= link_to (h log.user.display_name), [:admin, log.user] %></td>
    <td><%= log.created_at.to_s %></td>
  </tr>
<% end %>

Published on October 24, 2008 in Programming
2 Comments

Mailbuild gem 1.1

I’ve pushed a small update to the Mailbuild gem this morning which adds support for multiple subscriber lists, enabling you to manage different types of subscribers from within your application.

The sample Rails application has also been updated to take into account the slightly changed syntax for specifying your list id(s);

Mailbuild.list_id = 'LIST_ID_HERE'

…is now…

Mailbuild.list_ids = {:newsletter = 'LIST_ID_HERE'}

All API calls take a list id as their last parameter, which defaults to the first id you declare in the list_ids hash.

You can use a specific subscriber list id as follows;

Mailbuild.add(params[:email], params[:name], Mailbuild.list_ids[:newsletter])

The documentation explains what parameters each method accepts.

Published on September 3, 2008 in Programming
Comments Off

ISOdata Rails plugin

For anyone working on a Rails application which deals with countries or languages, the official source of data is the International Standards Association, specifically ISO 3166 for countries and ISO 639 for languages.

To make it easier to get this data into your Rails application, I’ve created two generators which automatically create the models, migrations and data you’ll need and bundled them up in a handy Rails plug-in.

Usage couldn’t be simpler…

script/plugin install git://github.com/cameronyule/isodata.git

If you want country data…

script/generate countries
rake db:migrate
rake isodata:db:countries

…and for languages…

script/generate languages
rake db:migrate
rake isodata:db:languages

Check out the isodata project on Github.

Published on August 5, 2008 in Programming
Comments Off

Rails 2.1 SWFUpload Example

There’s been a few posts lately on getting SWFUpload working with Rails 2.1, attachment_fu and the restful-authentication plugins.

To try and make things easier, I’ve made a sample – albeit basic – Rails application to show other people how I managed it.

I’ve created a project on Github to host it, feel free to check it out and let me know how you get on. The only instructions you should need are in the README file, but feel free to leave comments here if you do need a hand.

Published on July 31, 2008 in Programming
10 Comments

A Ruby/Rails interface to Mailbuild API

I’m pleased to announce the release of the first version of my Mailbuild API interface, which I’m distributing as a Rubygem.

To make it easier to figure out how to use it, I’ve also created a fully functional Rails application which demonstrates all the API calls available.

To use it all you have to do is grab a copy from subversion…

svn co http://mailbuild.rubyforge.org/svn/rails_mailbuild_example/

… make sure you have the mailbuild gem installed …

cd rails_mailbuild_example
# OS X/Linux users may have to prefix this with sudo
rake gems:install

… and edit config/initializers/mailbuild.rb, adding your own API key, List ID and sub-domain.

# You can get this information from your Mailbuild admin
Mailbuild.api_key = ''
Mailbuild.list_id = ''
Mailbuild.subdomain = ''

Hopefully that’s all there is to it, but if you run into any problems feel free to add a support request or bug report on Rubyforge.

Published on July 24, 2008 in Programming
Comments Off