views:

140

answers:

5

With a standard map.resource routing mechanics and several nested resources the resultant routes are unnecessarily long. Consider the following route:

site.org/users/pavelshved/blogs/blogging-horror/posts/12345

It's easy to create in routes.rb, and I'm sure it follows some kind of beneficial routing logic. But it's way too long and also seems like it's not intended to be human-readable.

A nice improvement would be to drop controller names, so it looks like:

site.org/pavelshved/blogging-horror/12345

Clear, simple, short. It may become ambiguous, but in my case I'm not going to name any user "users", for instance.

I tried setting :as => '', but it yields routes like this: site.org//pavelshved//blogging-horror//12345 when generating them by standard helpers.

Is there a way to map resources in such a way, that controller names become optional?

+2  A: 

The simplest way to get what you want would be to create a route in addition to your RESTful routes that acts as a shorthand:

map.short_blog ':user_id/:blog_id/:id', :controller => 'posts', :action => 'show'

You'll have to change the URL bits to work with how you're filtering the name of the user and the name of their blog. But then when you want to use the shorter URL you can use all the short_blog_* magic.

James Thompson
+1  A: 

Straight out of the default routes.rb:

map.connect 'products/:id', :controller => 'catalog', :action => 'view'

You could write:

map.connect ':user_id/:blog_id/:id', :controller => 'posts', :action => 'show'

But be sure to include that in the very end of the file, or it will try to match every three levels deep url to it.

Toms Mikoss
Does that mean that I should write these all routes in addition to that nice schema like `map.resources :users do |user| ; user.resources :blogs ; end`?
Pavel Shved
Yep. The named routes are just that - named. They expect to see controller name in the url (most of the times the ID of referenced object too). This route effectively says "OK, if you can't figure out the controller name from the URL, and it has 3 segments, just send it this way and map the segments to these parameters".
Toms Mikoss
A: 

Google "rails shallow routes" for information about this.

gdelfino
This doesn't do what is needed. I still want to emphasize that "blogs" belong to "users".
Pavel Shved
+1  A: 

Try this

map.pavelshved '/pavelshved/', :controller => :users, :action => view or
map.pavelshved '/:id', :controller => :users, :action => show do | blogs|
  blogs.bloging '/:id', :controller => :blogs, :action => show do | post|
    post.posting '/:id', :controller => :posts, :action => show
  end
end

I hope it work :)

Kuya
And where are my "edit", "new" etc action?
Pavel Shved
+ :member => {:edit => get, :create => :any, :destroy => :delete}it just my suggestion
Kuya
+3  A: 

You're looking for the :path_prefix option for resources.

map.resources :users do |user|
  user.resources :blogs do |blog|
    blog.resources :posts, :path_prefix => '/:user_login/:blog_title/:id'
  end
end

Will produce restful routes for all blogs of this form: site.org/pavelshved/bogging-horror/posts/1234. You'll need to go to a little extra effort to use the url helpers but nothing a wrapper of your own couldn't quickly fix.

The only way to get rid of the posts part of the url is with named routes, but those require some duplication to make restful. And you'll run into the same problems when trying to use route helpers.

EmFi