public
Description: Conditional checks on Rails filters
Clone URL: git://github.com/thoughtbot/when.git
cpytel (author)
Fri Feb 15 04:42:53 -0800 2008
commit  7f16b88604c6780e81bff5a887ed3c3af60d6f19
tree    832a4783496ae4153a720442e810f07bb79de2f3
parent  161cc080e7141aeddecfcdb75bb3c3d1ecf3d27e
when /
name age message
file MIT-LICENSE Wed Feb 13 16:25:45 -0800 2008 updated the README [jcarroll]
file README Fri Feb 15 04:42:53 -0800 2008 add thoughtbot to the copyright line [cpytel]
file Rakefile Mon Feb 11 18:43:52 -0800 2008 test and README files [dcroak]
file init.rb Mon Feb 11 22:32:55 -0800 2008 refactoring tests [dcroak]
file install.rb Mon Feb 11 18:23:48 -0800 2008 added when plugin skeleton [dcroak]
directory lib/ Thu Feb 14 21:36:09 -0800 2008 fixed callbacks String condition [jcarroll]
directory test/ Thu Feb 14 21:36:09 -0800 2008 fixed callbacks String condition [jcarroll]
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 and ActionController filters. It works exactly 
the way as the current implementation of #validates_acceptance_of.

It works on the 12 regular 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

3 validations:

validate
validate_on_create
validate_on_update

and 1 filter:

before_filter

It works when :if or :unless is passed a Symbol, a Proc or a String.
They return or evaluate to a true or false value.

Example
=======

class Address < ActiveRecord::Base

  before_save :geolocate

  def geolocate
    if 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

before_create's single responsibility is to execute code WHEN certain conditions are met.
geolocate's single responsibility is to ... geolocate. It should not contain its own
preconditions. 

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

before_create :encrypt_password,
  :unless => lambda {|user| user.password_confirmation.blank?}

before_filter :log_in!,
  :only => [:new, :create],
  :unless => :logged_in?

What When does NOT support
==========================

# ActiveRecord Class callbacks
before_create PasswordEncryptor,
  :unless => lambda {|user| user.password_confirmation.blank?}

# ActionController Class filters
before_filter Authorizer,
  :unless => :logged_in?

When will not work if your code contains any of these.

In our experience we've never used class callbacks or filters and find them to be overkill.

Installation
============

piston import https://svn.thoughtbot.com/plugins/when/trunk vendor/plugins/when

Copyright (c) 2008 Jared Carroll, Dan Croak, and thoughtbot, inc. released under the MIT license