This project is archived and is in readonly mode.
add support for shallow nesting of resource routes
Reported by S. Brent Faulkner | August 26th, 2008 @ 07:20 AM | in 2.x
UPDATED: I've edited this post to reflect the current patch... the original post is still included after this for the record.
Attached is a patch for resource mapping (and appropriate tests) that implements (optional) shallow nesting for resources. This allows you to specify :shallow => true for a resource. The option is inherited by any nested resources and causes any member routes (those with an id parameter) to not require the parent path prefix.
So, you can now...
map.resources :projects, :shallow => true do |project|
project.resources :milestones do |milestone|
milestone.resources :features do |feature|
feature.resources :tasks
end
end
end
In addition, the patch enhances the has_many shorthand notation to allow use of a hash to specify multiple levels of nested resources, which can be combined with the :shallow option as follows...
map.resources :projects, :has_many => { :milestones => { :features => :tasks } }, :shallow => true
vvvvv original post vvvv
The attached patch adds support for specifying a subset of named routes to create when mapping verb-oriented controllers for collections of resources.
You can specify which routes to add using :only and/or :except options with array values containing symbols of :collection, :new, :member and :associations.
This is especially useful for creating nested routes, so that the redundant parent ids are not required for routes containing explicit ids.
For example...
map.resources :posts do |post|
post.resources :comments, :only => [ :collection, :new ]
end
map.resources :comments, :except => [ :collection, :new ]
The generated routes would nest the collection and new record routes for comment resources within posts...
e.g. GET /posts/1/comments or POST /posts/1/comments
However, the routes with explicit ids would not require the post_id...
e.g. GET /comments/2 instead of GET /posts/1/comments/2
This really helps to clean up urls when nesting resources more than once.
For example, instead of:
map.resources :projects do |project|
project.resources :milestones do |milestone|
milestone.resources :features do |feature|
feature.resources :tasks
end
end
end
You could use:
map.resources :projects do |project|
project.resources :milestones, :only => [ :collection, :new ]
end
map.resources :milestones, :except => [ :collection, :new ] do |milestone|
milestone.resources :features, :only => [ :collection, :new ]
end
map.resources :features, :except => [ :collection, :new ] do |feature|
feature.resources :tasks, :only =>[ :collection, :new ]
end
map.resouces :tasks, :except => [ :collection, :new ]
This would result in the ability to simply access:
/features/72/tasks
Instead of:
/projects/13/milestones/16/features/72/tasks
Comments and changes to this ticket
-
RSL August 15th, 2008 @ 01:39 AM
Or [and I'm going on a limb here] you could just not make that resource nested so deep. http://weblog.jamisbuck.org/2007...
-
S. Brent Faulkner August 15th, 2008 @ 01:45 AM
Actually that is the purpose of the selective routes.
Jamis's proposed solution to the problem winds up doubly mapping the routes... so there is one route for /projects/1/milestones/2 and a second for /milestones/2
By selectively mapping them, the show_milestones route exists... the show_project_milestones routes does not.
(and my example was an exageration on purpose ;-)
-
RSL August 15th, 2008 @ 02:15 AM
I admit I was blinded by that last URL. If the goal of this is to DRY up the routing there while encouraging a more direct routing where possible, I'd like to see something more akin to
map.resources :users do |user| # Yes, this is rather hideous. user.resources :comments, :nest => [:collection, :new], :flat => [:member] end
or
# A little better. ;) map.resources :users, :nest => {:comments => [:collection, :new]
Apologies for my completely kneejerk reaction to seeing "nested resource" and that last URL. ;)
-
S. Brent Faulkner August 15th, 2008 @ 03:22 AM
How about using a notation similar to that used for ActiveRecord#find :includes
We could then use...
map.resources :projects => { :milestones => { :features => :tasks } }
Instead of the deeply nested blocks of my previous example.
Then, to get the flattening, we could just add a boolean option...
map.resources :projects => { :milestones => { :features => :tasks } }, :flatten => true
Personally, I wouldn't mind the :flatten option defaulting to true and requiring :flatten => false to get the "legacy" style of routes.
Thoughts?
-
S. Brent Faulkner August 15th, 2008 @ 03:32 AM
Hmmm... just remembered the addition of has_many and has_one...
So, I guess I'm suggesting the following...
map.resources :projects, :has_many => { :milestones => { :features => :tasks } }, :flatten => true
Again, I guess the default could be to flatten, but this would mean that we're changing an existing behaviour for the simple case...
map.resources :posts, :has_many => :comments
(which I don't think is a good idea -- ie. changing the existing behaviour -- so, I can live with needing to explicitly specify :flatten => true :-)
I think I'll try and build up a patch for this version instead...
-
S. Brent Faulkner August 16th, 2008 @ 12:52 PM
OK... how about this? I've attached a new patch for resource mapping (and appropriate tests) that implements (optional) shallow nesting for resources.
This allows you to specify :shallow => true for a resource. The option is inherited by any nested resources and causes any member routes (those with an id parameter) to not require the parent path prefix.
So, you can now...
map.resources :projects, :shallow => true do |project| project.resources :milestones do |milestone| milestone.resources :features do |feature| feature.resources :tasks end end end
or...
map.resources :projects, :has_many => { :milestones => { :features => :tasks } }, :shallow => true
Much nicer than my original proposal.
In either case, I'd be able to access resources with paths like the following...
/projects /projects/1 /projects/1/milestones /milestones/2 /milestones/2/features /features/56/tasks/new
(no redundant parent_id parameters... just what's required)
-
S. Brent Faulkner August 16th, 2008 @ 01:13 PM
- Title changed from add support for selective resource routes to add support for shallow nesting of resource routes
-
DHH August 16th, 2008 @ 08:45 PM
Really nice. Shallow is a great term for it too. It needs documentation, though. Then I'd say it would be ready to go. Nice work.
-
S. Brent Faulkner August 17th, 2008 @ 05:14 AM
Thanks again, David.
I've attached a new patch with:
a) documentation
b) the support for passing deep :has_many information using a hash/array
for example:
map.resources :projects, :has_many => { :milestones => { :features => :tasks } }, :shallow => true
-
S. Brent Faulkner August 17th, 2008 @ 05:50 AM
regarding (b) ... I had actually thought that this was already supported, but must have been thinking of the ActiveRecord finder :include option, so added it in since that was was part of the beauty of this solution
-
S. Brent Faulkner August 19th, 2008 @ 03:54 PM
tests pass, documentation included, please consider for commit
(hey, dhh thought it was ok :-)
-
S. Brent Faulkner August 22nd, 2008 @ 04:06 AM
patch would not apply... fixed... uploaded new patch.
-
Pratik August 28th, 2008 @ 05:04 PM
- Assigned user set to Pratik
-
S. Brent Faulkner August 30th, 2008 @ 05:29 AM
I saw a recent commit to resources.rb and tested the patch. It wouldn't apply again, so I've rebased and attached the new one...
-
Repository August 30th, 2008 @ 03:22 PM
- State changed from new to resolved
(from [83c6ba18899a9f797d79726ca0078bdf618ec3d4]) Add support for shallow nesting of routes. [#838 state:resolved]
Adds :shallow option to resource route definition. If true, paths for nested resources which reference a specific member (ie. those with an :id parameter) will not use the parent path prefix or name prefix.
Example :
map.resources :users, :shallow => true do |user| user.resources :posts end
-
GET /users/1/posts (maps to PostsController#index action as usual) named route "user_posts" is added as usual.
-
GET /posts/2 (maps to PostsController#show action as if it were not nested) Additionally, named route "post" is added too. http://github.com/rails/rails/co...
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>
People watching this ticket
Attachments
Tags
Referenced by
- 838 add support for shallow nesting of resource routes (from [83c6ba18899a9f797d79726ca0078bdf618ec3d4]) Add sup...