Project

changey

0.01
No commit activity in last 3 years
No release in over 3 years
An Active Record extension to provide state callbacks
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

>= 4.2, < 7
 Project Readme

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