Get rake routes to recognize constraint classes in rails
I’ve been playing recently with the new rails-3 route constraints behaviour. Quite nice, actually, I really enjoy being able to add total custom code to determine if a route match. Of course (?), my first use of that has been subdomain constraints. Here is an example :
constraints( ClientSubdomain ) do resource :organization, :only => %w( show edit update destroy ) do get 'close', :on => :member end root :to => 'static_page#get_page', :page => 'home_client' end constraints( AdminSubdomain ) do scope :module => 'admin' do resources :organizations end root :to => 'admin/organizations#index' end
So here, if I’m on the admin subdomain, I can handle multiple organizations, my clients ones. And if I am on a client subdomain, the organization resource is a singleton (client must only handle its own organization, right?).
Ok, let’s see what rake routes outputs.
close_organization GET /organization/close(.:format) {:action=>"close", :controller=>"organizations"}
edit_organization GET /organization/edit(.:format) {:action=>"edit", :controller=>"organizations"}
organization GET /organization(.:format) {:action=>"show", :controller=>"organizations"}
PUT /organization(.:format) {:action=>"update", :controller=>"organizations"}
DELETE /organization(.:format) {:action=>"destroy", :controller=>"organizations"}
root /(.:format) {:action=>"get_page", :controller=>"static_page"}
organizations GET /organizations(.:format) {:action=>"index", :controller=>"admin/organizations"}
POST /organizations(.:format) {:action=>"create", :controller=>"admin/organizations"}
new_organization GET /organizations/new(.:format) {:action=>"new", :controller=>"admin/organizations"}
GET /organizations/:id/edit(.:format) {:action=>"edit", :controller=>"admin/organizations"}
GET /organizations/:id(.:format) {:action=>"show", :controller=>"admin/organizations"}
PUT /organizations/:id(.:format) {:action=>"update", :controller=>"admin/organizations"}
DELETE /organizations/:id(.:format) {:action=>"destroy", :controller=>"admin/organizations"}
root /(.:format) {:action=>"index", :controller=>"admin/organizations"}
Erf, not really helpful.
After playing a while with mapper, routeset and routes, I came to a solution.
Monkey patch for Constraints
First, we need to expose Constraints#constraints to the world. Create a lib/route_constraints.rb:
module ActionDispatch module Routing class Mapper class Constraints attr_reader :constraints end end end end
Be sure to require it in config/environment.rb.
Rake task
Then, put this content in lib/tasks/route_with_constraints.rake:
Gist
namespace :routes do desc 'Print out all defined routes in match order, with names, per constraint class. Target specific constraint class with CONSTRAINT=x. Target specific controller with CONTROLLER=x.' task :constrained => :environment do Rails.application.reload_routes! constraints_routes = Hash.new Rails.application.routes.routes.each do |route| group = (route.app.class == ActionDispatch::Routing::Mapper::Constraints ? route.app.constraints.to_s : 'No constraint class') constraints_routes[group] ||= [] constraints_routes[group] < < route end requested_constraint = ENV['CONSTRAINT'] constraints_routes.each do |group, all_routes| if requested_constraint.nil? or group == requested_constraint puts "\n\nConstraint class : #{group}\n\n" if ENV['CONTROLLER'] all_routes = all_routes.select{ |route| route.defaults[:controller] == ENV['CONTROLLER'] } end routes = all_routes.collect do |route| reqs = route.requirements.dup reqs[:to] = route.app unless route.app.class.name.to_s =~ /^ActionDispatch::Routing/ reqs = reqs.empty? ? "" : reqs.inspect {:name => route.name.to_s, :verb => route.verb.to_s, :path => route.path, :reqs => reqs} end routes.reject! { |r| r[:path] =~ %r{/rails/info/properties} } # Skip the route if it's internal info route name_width = routes.map{ |r| r[:name].length }.max verb_width = routes.map{ |r| r[:verb].length }.max path_width = routes.map{ |r| r[:path].length }.max routes.each do |r| puts "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}" end end end end end
Ok, now we have a rake routes:constrained task. Let see its output :
Constraint class : No constraint class
Constraint class : AdminSubdomain
organizations GET /organizations(.:format) {:action=>"index", :controller=>"admin/organizations"}
POST /organizations(.:format) {:action=>"create", :controller=>"admin/organizations"}
new_organization GET /organizations/new(.:format) {:action=>"new", :controller=>"admin/organizations"}
GET /organizations/:id/edit(.:format) {:action=>"edit", :controller=>"admin/organizations"}
GET /organizations/:id(.:format) {:action=>"show", :controller=>"admin/organizations"}
PUT /organizations/:id(.:format) {:action=>"update", :controller=>"admin/organizations"}
DELETE /organizations/:id(.:format) {:action=>"destroy", :controller=>"admin/organizations"}
root /(.:format) {:action=>"index", :controller=>"admin/organizations"}
Constraint class : ClientSubdomain
close_organization GET /organization/close(.:format) {:action=>"close", :controller=>"organizations"}
edit_organization GET /organization/edit(.:format) {:action=>"edit", :controller=>"organizations"}
organization GET /organization(.:format) {:action=>"show", :controller=>"organizations"}
PUT /organization(.:format) {:action=>"update", :controller=>"organizations"}
DELETE /organization(.:format) {:action=>"destroy", :controller=>"organizations"}
root /(.:format) {:action=>"get_page", :controller=>"static_page"}
Way better :)
30 janvier, 2011 à 15:23
[...] Get rake routes to recognize constraint classes in rails - Olivier El Mekki blog.olivier-elmekki.com/2011/01/30/get-rake-routes-to-recognize-constraint-classes-in-rails/ – view page – cached Blog français de Olivier El Mekki Tags [...]