2

I am using Rails 3. And I'm wondering how to pass params to some blocks in routes.rb.

What I'm trying to do is to make a catch all route, that check from slugs database the model name of it by the id.

After getting the model name i pluralize it to get the controller name.

match '/:id', :controller => proc { Slug.find_by_iid(params[:id]).model.pluralize }, :action => :show

The table slugs

model    iid
-----    -----
post     4d2c7de0c5abe7f8a9000007
item     4d2c7de0c5abe7f809000004

When I try to access some pages like /4d2c7de0c5abe7f8a9000007 I got this error:

Started GET "/4d2c7de0c5abe7f8a9000007" for
127.0.0.1 at 2011-01-12 00:04:31 +0200

ActionController::RoutingError (wrong constant name #<Proc:0x0000010337c310@):

Rendered /Users/amr/.rvm/gems/ruby-1.9.2-p136@rails3/gems/actionpack-3.0.3/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (1.2ms)

The expected is to point to posts#view with iid: 4d2c7de0c5abe7f8a9000007

amrnt
  • 1,331
  • 13
  • 30

2 Answers2

8

proc returns a Proc, but match is expecting a string. You could try adding .call to have the proc return its value. Though I'm not sure if this will end up calling the proc each time or only when routes is loaded...

EDIT

Seems I was way off-base with my earlier response and comments. Maybe something like this?:

match '/:id', :to => proc { |env|
  id = env["action_dispatch.request.path_parameters"][:id]
  model = Slug.find_by_iid(id).model
  controller = [model.pluralize.camelize,"Controller"].join.constantize
  controller.action("show").call(env)
}

Though this really ought to be defined in a library and included. Perhaps someone knows a better way?

zetetic
  • 47,184
  • 10
  • 111
  • 119
  • I could remove `proc` like this `:controller => Slug.find_by_iid(params[:id]).model.pluralize` but still the problem is how to get `params[:id]` value. When i try to run the app it throws me an error `../config/routes.rb:6:in `block in ': undefined local variable or method `params' for # (NameError)` – amrnt Jan 11 '11 at 22:30
  • when i made it `controller => proc { Slug.find_by_iid(params[:id]).model.pluralize }.call` it threw me `/config/routes.rb:6:in `block (2 levels) in ': undefined local variable or method `params' for # (NameError)` ALSO! – amrnt Jan 11 '11 at 23:15
  • Ahh, I missed the `params` in there. I don't think that works -- `params` is set in the controller, not the routing engine. Take a look at the answer here: http://stackoverflow.com/questions/2596312/dynamic-url-controller-mapping-for-routes-in-rails – zetetic Jan 11 '11 at 23:59
  • Thanks. I already read it before, not the solution that am looking for! – amrnt Jan 12 '11 at 00:55
  • 1
    Evolution of this solution. http://stackoverflow.com/questions/5641786/testing-rack-routing-using-rspec – Agustin Mar 30 '12 at 17:23
0

Putting this in your routes seems really hacky. I would recommend creating a Slugs controller, passing this task onto that, and redirecting to the appropriate controller from there. Assuming your other pages use standard RESTful routes, you could do something like this:

Change route to this:

match '/:id', :controller => :slugs, :action => :show

Slugs controller:

def show
  slug = Slug.find_by_iid(params[:id])

  redirect_to send("#{slug.model}_url", params[:id])
end
Peter Brown
  • 50,956
  • 18
  • 113
  • 146
  • I dont want to make redirect dude! I just want to make the application understand my slug, and load the related model. like in facebook.com and quora.com – amrnt Jan 12 '11 at 00:43