[转]ROR 中的Nesting resources

http://weblog.jamisbuck.org/2007/2/5/nesting-resources

The RESTful routes feature in Rails makes it really, really simple to nest resources within each other. Just give a block to the “map.resources” call, and define further resources on the value yielded to that block:

map.resources :accounts do |accounts|
  accounts.resources :people do |people|
    people.resources :notes do |notes|
      notes.resources :comments
    end
  end
end

That monstrosity would allow you to define routes like:

accounts_url         #-> /accounts
account_url(1)       #-> /accounts/1
people_url(1)        #-> /accounts/1/people
person_url(1,2)      #-> /accounts/1/people/2
notes_url(1,2)       #-> /accounts/1/people/2/notes
note_url(1,2,3)      #-> /accounts/1/people/2/notes/3
comments_url(1,2,3)  #-> /accounts/1/people/2/notes/3/comments
comment_url(1,2,3,4) #-> /accounts/1/people/2/notes/3/comments/4

Simple! However, in using RESTful routes more and more, I’m coming to realize that this is not a best practice. Rule of thumb: resources should never be nested more than 1 level deep. A collection may need to be scoped by its parent, but a specific member can always be accessed directly by an id, and shouldn’t need scoping (unless the id is not unique, for some reason).

Think about it. If you only want to view a specific comment, you shouldn’t have to specify the account, person, and note for the comment in the URL. (Permission concerns can come into this, to some degree, but even then I’d argue that judicious use of the session is better than complicating your URLs.) However, if you want to view all comments for a particular note, then you do need to scope the request by that note. Given the above nesting of routes, I’m finding the following a better (if slightly more verbose) method:

map.resources :accounts do |accounts|
  accounts.resources :people, :name_prefix => "account_"
end

map.resources :people do |people|
  people.resources :notes, :name_prefix => "person_"
end

map.resources :notes do |notes|
  notes.resources :comments, :name_prefix => "note_"
end

map.resources :comments

You’ll notice that I define each resource (except accounts) twice: once at the top level, and once nested within another resource. For the nested resources, I also give a “name_prefix”—this gets tacked onto the front of the named routes that are generated.

So, the above mappings give you the following named routes:

accounts_url          #-> /accounts
account_url(1)        #-> /accounts/1
account_people_url(1) #-> /accounts/1/people
person_url(2)         #-> /people/2
person_notes_url(2)   #-> /people/2/notes
note_url(3)           #-> /notes/3
note_comments_url(3)  #-> /notes/3/comments
comment_url(4)        #-> /comments/4

The URL’s are shorter, and the parameters to the named routes are much simpler. It’s an all-around win! I won’t go so far as to say that resources should never be deeply nested, but I will say that you should think long and hard before you go that route.

用户评论也值得一看。

你可能感兴趣的:(resource)