arrow_backward Back to blog

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 😛

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.


New Project Request