public
Description: Conditional checks on Rails filters
Clone URL: git://github.com/thoughtbot/when.git
dcroak (author)
Mon Feb 11 18:43:52 -0800 2008
commit  edbcecf6e3e769d1b526795d64ef65dc2680f685
tree    5237edd818a72386f5c6f3e2811bcaebf15d3d4e
parent  74f68a2f1c6b2d6679cd93b4ad4a3dba13acc2df
when /
name age message
file MIT-LICENSE Mon Feb 11 18:23:48 -0800 2008 added when plugin skeleton [dcroak]
file README Mon Feb 11 18:43:52 -0800 2008 test and README files [dcroak]
file Rakefile Mon Feb 11 18:43:52 -0800 2008 test and README files [dcroak]
file init.rb Mon Feb 11 18:37:39 -0800 2008 directory structure [dcroak]
file install.rb Mon Feb 11 18:23:48 -0800 2008 added when plugin skeleton [dcroak]
directory lib/ Mon Feb 11 18:37:39 -0800 2008 directory structure [dcroak]
directory tasks/ Mon Feb 11 18:23:48 -0800 2008 added when plugin skeleton [dcroak]
directory test/ Mon Feb 11 18:43:52 -0800 2008 test and README files [dcroak]
file uninstall.rb Mon Feb 11 18:23:48 -0800 2008 added when plugin skeleton [dcroak]
README
When
====

When adds :if and :unless conditions to ActiveRecord callbacks 
and validations. It works exactly the way as the current implementation 
of validates_acceptance_of.

It works on all 14 callbacks:

before_validation
before_validation_on_create
after_validation
after_validation_on_create
before_save
before_create
before_update
after_create
after_update
after_save
before_destroy
after_destroy
after_initialize
after_find

and 3 validations:

validate
validate_on_create
validate_on_update

It works when :if or :unless is passed symbols, lambdas, and strings.
They should return or evaluate to a true or false value.

Example
=======

class Address < ActiveRecord::Base
  before_save :geolocate

  def geolocate
    if self.complete?
      ...
    end
  end

  def complete?
    street? && city? && state? && zip?
  end
end

In this case, we want to find the latitude and longitude of an address only if 
the address is complete.

Wrapping the entirety of a callback method with conditional logic is bad form.
The callback should execute WHEN the model's life cycle reaches its 
"before_save" point and WHEN its address is "complete."

With When, the WHEN responsibility is moved to where it belongs:
as part of the callback.

class Address < ActiveRecord::Base
  before_save :geolocate, :if => :complete?

  def geolocate
    ...
  end

  def complete?
    street? && city? && state? && zip?
  end
end

The callback's single responsibility is to execute code WHEN certain conditions are met.
The geolocate method's single responsibility is to ... geolocate.

More Examples
=============

after_update :send_notifications, :unless => lambda {|record| record.minor_change?}

after_initialize :capitalize_title, :if => :new_record?

before_create %{self.password = password.to_sha1},
  :unless => lambda {|user| user.password_confirmation.blank?}

before_create :unless => lambda {|user| user.password_confirmation.blank?} do |record|
  record.password = record.password.to_sha1
end

before_create PasswordEncryptor, :unless => lambda {|user| user.password_confirmation.blank?}
class PasswordEncryptor
  def self.before_create(record)
    record.password = record.password.to_sha1
  end
end


Copyright (c) 2008 Jared Carroll, released under the MIT license