public
Description: Conditional checks on Rails filters
Clone URL: git://github.com/thoughtbot/when.git
jcarroll (author)
Thu Feb 14 17:39:03 -0800 2008
commit  432aa3e537c75fa52a742877a6623b92383ebade
tree    811963e5d9a159857f617c12789a481e5eb5e0c2
parent  21620772650ee3d94718db5faefd682be99f70d5
when /
name age message
file MIT-LICENSE Wed Feb 13 16:25:45 -0800 2008 updated the README [jcarroll]
file README Thu Feb 14 15:29:04 -0800 2008 added installation instructions [dcroak]
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 17:39:03 -0800 2008 added support for String callbacks and filters [jcarroll]
directory test/ Thu Feb 14 17:39:03 -0800 2008 added support for String callbacks and filters [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 String callbacks
before_create 'self.password = password.to_sha1',
  :unless => lambda {|user| user.password_confirmation.blank?}

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

# ActiveRecord Block callbacks
before_create(:unless => lambda {|user| user.password_confirmation.blank?}) do |record|
  record.password = record.password.to_sha1
end  

# ActionController Block filters
before_filter(:unless => :logged_in?) do |controller|
  redirect_to new_session_path
end

# 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 any of these types of callbacks and filters.  By using Symbols, i.e. methods,
the resulting code is much more intention revealing.  Class callbacks and filters we feel are most of the time overkill.


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

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

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