param with map.resources

Hi all,

With ye olde routes, you could do stuff like:

  map.connect '/foo/:id', :controller => 'bar', :type => 'foo'

but you can't pass arbitrary params into #resources:

  map.resources :foo, :controller => 'bar', :type => 'foo' # bonk!

the :controller key works fine, but :type is just ignored. This would
be very handy for an STI-backed controller I have, to change a url
like "/bar/new?type=foo" to "/foo/new" but still handle it with

I've seen a few people ask this question, eg.

but no answers. I've tried a bunch of stuff
with :requirements, :as, :path_prefix, and nesting, but all to no
avail. If anyone has any advice, I'd be most grateful.


It might be helpful if you gave a few more examples of what you want
to accomplish. Are you trying to have the following routes all point
to the "new" method on the same controller?


Greg DeVore

Sure. You have it basically right, but let me elaborate.

I have models like so:

class Papa < ActiveRecord::Base; abstract_class = true; end
class Daughter < Papa; end
class Son < Papa; end

I have this controller:

class PapaController < ApplicationController
  def new; @model = new_model; end
  def new_model
    params[:type] # there's more safety logic
here in reality, but this is the gist

I started with the default route:

  map.resources :papa

So, then, I can create a new son by doing GET /papa/new?type=son,
which is fine, but not ideal. Ideally, I would do GET /son/new, but it
would still use the Papa controller, and set params[:type] to "son".
This is what I have right now:

  map.resources :papa, :path_prefix => '/:type'

which allows me to GET /son/papa/new, and create links like
papa_path(@model.type.to_s.downcase, @model).

So the question is how to make these specs pass:

  params_from(:get, "/son/new").should == {:controller => 'papa',
:action => 'new', :type => 'son'}
  params_from(:get, "/daughter/new").should == {:controller => 'papa',
:action => 'new', :type => 'daughter'}

Is that clearer?


I don't know how you would do that in the way you are describing. One possibility though would be to do this:

map.resources :sons, :controller => "papas"
map.resources :daughters, :controller => "papas"

This will point both routes to the papas controller. You won't see "sons" or "daughters" come through as params. But you can query request.env['REQUEST_URI'] and you would get back something like '/sons/new/'.

1. request.env['REQUEST_URI'].split("/") will give you an array ["","sons","new"]
2. access [1] of the array and you will have your parameter.

A little convoluted but I think that it would do what you want.


It sounds like you want to be using nested resources. Try something
like this

map.resources :papas, :has_many => [:sons, :daughters]

For more info read...

Wouldn't that give me "/papas/1/sons/new"? Not exactly what I'm
looking for if I understand it correctly, but thanks.

Sigh, yeah, there's always that way. So unrailsy... but probably what
I'll end up doing. Or I could patch Resources to make it push any
unclaimed options into params. But parsing the URI by hand is probably

Here's what I cooked, up. Wasn't that hard, and appears to work so far...

$ cat lib/param_resources.rb
module ParamResources
  def self.included base
    super base
    base.alias_method_chain :action_options_for, :params

  def action_options_for_with_params action, resource, method=nil
    action_options_for_without_params(action, resource, method).
      merge(resource.options[:params] || {})
$ cat config/routes.rb
ActionController::Routing::RouteSet::Mapper.send :include, ParamResources
ActionController::Routing::Routes.draw do |map|

  map.resources :papa
  map.resources :son, :controller => :papa, :params => {:type => "son"}
  map.resources :daughter, :controller => :papa, :params => {:type =>

I'd be interested in peoples' takes on it.