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
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.