Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
121 lines (83 sloc) 4.47 KB


Code Climate

CustomChangeMessages is a rails plugin for providing a nicely formatted log message recording any edits made to an active record object. This is based off of the ActiveRecord::Dirty module, making this plugin compatible with rails versions 2.1 and up. There is little to no configuration required, with all columns included by default (except for id, and created_at, updated_at timestamps), and belongs_to associations handled nicely with the default options configurable.


In a controllers #update action

def update
  @post = Post.find(params[:id])
  @post.attributes = params[:post]
  @changes = @post.change_messages
  # Use this array to either log history, display in a flash message, or in a mailer.
  # => ["Title has changed from 'Ruby on Rails plugin' to '[Update] Ruby on Rails plugin'", "Category has changed from 'Ruby' to 'Ruby on Rails'"]!


ActiveRecord extensions:

change_message_for(attribute) # Returns a string message representation of the attribute that has changed

change_messages # Returns an array of the messages for each changed attribute


gem install custom_change_messages

Rails 2.X

# config/environment.rb
config.gem "custom_change_messages"

Rails 3.X

# Gemfile
gem "custom_change_messages"

Requirements: active record, version 2.1 or greater, if you use an earlier version you can try using which backports the ActiveRecord::Dirty code that this gem depends on to earlier rails versions.

Detailed Example

The main use of this is to help clean up controller actions, such as:

class ItemsController < ApplicationController

  def update
    @item.attributes = params[:item]
    Mailer.deliver_item_update(@item, @item.change_messages.to_sentence)!

  rescue ActiveRecord::RecordInvalid => e
    flash[:error] = e.reord.error_messages
    redirect_to item_url(@item)


In this example we use attributes= instead of update_attributes because the change_messages functionality is required to be called before you save the object, detecting what is changed from the state read from the database. For more advanced uses, you can add in before_save hooks to log changed details for you.

@item.change_messages.to_sentence will return human readable mesages in a string format such as: => "Description has changed from 'Nice and easy' to 'This task is now rather long and arduous', User has changed from 'Jeremy' to 'Guy', and Due Date has been rescheduled from '09/11/2008' to '10/11/2008'"

The messages for each attribute are also customizable, which is especially handy for dealing with belongs_to assocations. Here's a more complicated example:

Use the custom_message_for method to customize the message for the attribute, specifying :display => :name will use the method/attribute :name for displaying the record that the item belongs to

The skip_message_for method can be used to prevent stop any changes to a particular attribute showing up

class Item < ActiveRecord::Base
  belongs_to :person

  custom_message_for :person, :display => :username # display the person's username instead of the id
  custom_message_for :due_on, :as => "Due Date", :message => "has been rescheduled", :format => :pretty_print_date
  # change the syntax of the message for working with dates, because it makes more sense that way

  # this method is used for formatting the due_on field when it changes
  def pretty_print_date(value = self.due_on)
class Person < ActiveRecord::Base
  custom_message_for :username, :as => "Name"
  skip_message_for :internal_calculation
p = Person.create!(:username => "Jeremy")
p2 = Person.create!(:username => "Optimus Prime")
i = Item.create!(:name => "My Task", :description => nil, :person => p, :due_on =>
i.attributes = {:person => p2, :description => "This task is difficult, might need some help"}

=> ["Due Date has been rescheduled from '4/12/2008' to '5/12/2008'", "Person has changed from 'Jeremy' to 'Optimus Prime'", "Description has changed from '' to 'This task is difficult, might need some help'"]

Copyright (c) 2008 Jeremy Olliver, released under the MIT license