tag routing, rails 3, constraints

Use lambdas for Rails 3 Route Constraints

I love the new constraints feature of Rails 3 routing. It opens up powerful new avenues for handling certain scenarios before a request is even delivered to the controller. One thing that bugs me, though, is that making a new class for any non-standard request-based constraint is kind of a pain. Rather than this:

class SignedInConstraint
  def self.matches?(request)
    !request.session[:user_id].blank?
  end
end

root :to => 'controller#index', :constraints => SignedInConstraint

I'd much rather be able to simply write:

root :to => 'controller#index', :constraints => lambda{|req| !req.session[:user_id].blank?}

So I mentioned wanting to patch Rails to make this work in Presently and got a brilliantly pragmatic response from fellow Intridean Jeremy McAnally:

Jeremy: class Proc; alias :matches? :call; end; # No clue if this would work :P

Update: As Jose Valim pointed out, this is actually built in to the Rails 3 source. While I wasn't aware of this feature, after calling matches? it will check for call. So you can do this with no core class modification...it just works!

scope :constraints => lambda{|req| !req.session[:user_id].blank? } do
  # all my logged in routes
end

This post started out as a simple core class hack to enable some new functionality in Rails. Now it's been transformed into an announcement: Rails 3 supports lambda routing constraints by default! Bonus points to the Rails core team for thinking this through well before I tried to hack it.