Run callbacks based on changes to attributes in Active Record
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib
spec
Gemfile
Gemfile.lock
MIT-LICENCE
README.md
changey.gemspec

README.md

Changey

Changey works with Active Record and allows you to trigger certain callbacks based on the changes of attributes on the model. For example, when a user is given an suspended_at timestamp, you may wish to enforce other validations or run callbacks.

class User < ActiveRecord::Base

  when_attribute :suspended_at, :changes_from => nil do
    validate do
      if suspended_at < Time.now
        errors.add :suspended_at, "cannot be set in the past"
      end
    end

    after_commit do |was, now|
      UserMailer.suspension_notice(self).deliver_later
    end
  end

end

Installation

Just add the gem to your Gemfile.

gem 'changey', '>= 0.0.0'

Usage

To choose what changes you wish to track, you call a when_attribute method and provide it with some expectations. Here's an example of some of the expectations you might work with.

# Whenever the name changes to any other value
when_attribute :name, :changes_to => :anything

# Whenever the name attribute changes from 'Adam' to any other value
when_attribute :name, :changes_from => "Adam"

# Whenever the name attribute changes to 'Adam' from any other value
when_attribute :name, :changes_to => "Adam"

# Whenever the name attribute changes from 'Adam' to 'Michael'
when_attribute :name, :changes_from => 'Adam', :to => 'Michael'

# Whenever the name attribute changes to 'Michael' from 'Adam' (same as above)
when_attribute :name, :changes_to => 'Michael', :from => 'Adam'

These examples show all your expectation values as strings however you can also use Arrays, Regular Expressions & Procs in place of these. Here's some examples:

# Whenever the name attribute changes from 'Adam' or 'Eve' to any value
when_attribute :name, :changes_from => ['Adam', 'Eve']

# Whenever the name attribute changes from a name beginning with an P
when_attribute :name, :changes_from => /\A[P]/i

# Whenever the name attribute changes to something that passed an external check
when_attribute :name, :changes_to => Proc.new { |value| SomeCheck.check(value) }

In addition to provide your expectations, you also need to provide a block which allows you to choose the behaviour to be executed when the change occurs.

The callbacks which are supported within the when_attribute block are:

  • validate - called as part of the validation.
  • before_save - called after validation before the record is saved.
  • after_save - called after the save has been completed.
  • after_commit - called after the record has been committed.

When calling one of these types of callback you can either provide a block or the name of a method to execute. For example:

when_attribute :suspended_at, :changes_from => nil do
  validate :do_some_validation
end

When you provide a block, you'll be provided with the previous and current value of the attribute which you are tracking. This is espically useful in an after_commit callback where Active Record's tracking of attributes has been reset already.

when_attribute :suspended_at, :changes_to => nil do
  after_commit do |time_originally_suspended, now|
    UserMailer.unsuspension(self, time_originally_suspended).deliver_later
  end
end