What criteria do you use to decide whether or not to nest resources?
In the past, I have chosen to nest when the index action on a resource makes no sense without scoping to an associated resource (the parent).
Even as I write the above criteria, I realize it is ambiguous at best.
A colleague has stated:
Nest resources because it captures the relationship of the associated models visually in the url structure... And it makes it easy to modify the url to get back to just the post. If I see /posts/123/offers/555 -- I know that I can go to /posts/123 to see my post. Where as if I just saw /offers/555, I'd have no way to get back to the post other than manually navigating through the site.
To me, manipulation of the url by users should have no bearing on the architecture of the application, and flies against what I understand to be the generally held principle that nested resources should be avoided if at all possible. Additionally, this argument would seem to support multiple levels of nesting, which again, pretty much every article I read advises against.
What has been your experience?
I nest routes, as you put it first, when the later things in the route doesn't make sense without the former. Comments on a blog would be nested under resources articles because, though perhaps you want display an individual comment on it's own page (who knows why...), a comment belongs to an article.
This also has controller implementations. If you know the article, then you can find the specific comment scoped to the article. This makes for more effective queries.
Also, your colleague was correct that you have to deal with users messing around with your routes, though he had the wrong reason. It isn't for their convenience, but for their security.
Let's take an Amazon-like app with users and orders. If I am at users/5/orders/2 then I think "hey! I can just change that 5 to a 4 and then see someone else's orders!" If you don't scope orders, then the controller-level logic for authorizing a user to view orders/2 becomes far trickier. Scoping to the user allows for current_user.orders.find(params[:id]) in the orders controller. Current user can be found based on authentication so that they cannot just swap ids in the URL and become someone else.
Related
In situations where the resource id can be identified by other means (such as current_user for pages that require authentication), is it a good idea to omit the id from the url? (For example, /students/1/homework to /students/homework).
Also, would this have any impact on the restfulness of the urls? I am suspecting it does for HTTP verbs, but for custom actions I am not so sure.
I suppose it is down to your application and what is useful for clients to see. If your connecting user is an admin who can see all students homework, then the /students/1/homework path makes sense, however if it will only ever be students using this resource then the /students/homework makes more sense.
Essentially the latter could be thought of as a namespace for all student resources.
I have found it very useful to split these resources by namespaces as to not confuse client writers and keep your authorisation very clear (who can see/do what).
In your example, the 2 URIs identify different resources:
the homework of user #1,
the homework of the current user.
The choice depends a lot on which resource you think people will want to refer to (by e-mail or by bookmark for example).
I don't think the second solution is unRESTful, but I would prefer the first one, since it is compatible with a lot of additional features (e.g. teachers could access the representation of students' homework).
URLs should always point to one specific resource. They can either be absolute or relative. Think of it as a filesystem. In some cases (security/scalability) you can't allow listings.
Session-based / Relative resources /students/me, /students/latest, /students/latest/homework/lastest
Absolute resources /students/3, /students/3/homework, /teachers/3/homework/3
I'm trying to learn a bit more about creating friendly URLs, particularly in relation to something like an e-commerce site. If you take a look at this site as an example: http://www.wiggle.co.uk/
It basically lets you refine your search based on the categories. So if I go to http://www.wiggle.co.uk/mens/road-time-trial-bikes/ it will list all men's road bikes, if I then go to http://www.wiggle.co.uk/road-time-trial-bikes/ it will list men's and women's bikes, and if I go to http://www.wiggle.co.uk/bianchi-sempre-105/ it will display a particular bike.
I'm not really sure what the routing would look like for something like this, as you could have many filters in the URL. I'm also not sure how how it's able to distinguish between what's a filter and what's a product.
I'd say you are fairly close but would break out the second and third as it would be a little ambiguous for the one Action to interpret the two parameters. I'd suggest the following:
http://www.wiggle.co.uk/road-time-trial-bikes/
http://www.wiggle.co.uk/bikes/bianchi-sempre-105/
Thus /bikes/ could be routed clearly to a different controller and action. You would need to create a specific rule for the root or you could add a specific controller, say bike-types, to the first url
http://www.wiggle.co.uk/bike-types/road-time-trial-bikes/
The specifics on routing are well documented but a good place to start might be with writing some tests to help you understand what works and give you more confidence with making changes to your routes. It is very easy to create clashing routes and tests help prevent this.
http://mvccontrib.codeplex.com/wikipage?title=TestHelper#Routes
since I am only going to be showing that one item, do I just have (example)
/the_thing/23
or do I still go with the /the_group/1/the_thing/23
I know I need to appropriately nest and have associations for forms and using nested routes for links, but for a show page is my link to it nested or not?
i.e. should I still show it within the context of its master or just on it's own. In this case the resource cannot be updated without the nesting i.e. on it's own.
Will a main intent be to show links back to the group?
This question is ONLY about the show page.
This is just a matter of choice, you can even create both routes depending on the context.
You should just ask yourself if it makes more sense for the user to see one url or the other: it's sheer user experience here.
It's true that it's only a matter of choice.
But consider a case, you have a Post model and Comment model, and Comment is a nested resource of Post. It does not make sense to have a separate route for show action of Comment, as showing comments without the relevant post makes no sense.
Hence, it's case specific as well.
In the process of making an ebook, users have to edit its content, edit its metadata, choose marketing options, (such as pricing and distribution) and publish.
I started to put each everything inside the Book resource (contents, metadata, marketing options etc)
Then each step of the process (contents, metadata, marketing) is an action inside BooksController.
But Books started to grow a lot in terms of attributes and actions.
I'm wondering if it is better to force RESTfulness by creating singleton resources, each associated to their respective book.
The routes would be:
/book/12/content/edit
/book/12/metadata/edit
/book/12/marketing/edit
This seems more elegant, as each of these "resources" are RESTful and have few attributes each. But the resources are not objects (Marketings?).
Do you thing it's OK to create meaningless resources just to be RESTful and keep code in order?
Is there a better way to group similar attributes than create resources out of them? Thanks.
I'm porting a large PHP application to Rails and we have a fair few "ad-hoc"resources, such as admins have the ability to log in as another user with their permission, in order to correct issues etc. I would always complain that features such as logging in as other users should not be bundled into a huge monolithic AdminController as actions loginAsUser and logOutOfUserAccount. In our Rails app we try to visualize as much as we can in terms of resources, so using the example I just gave, we have an Admin namespace, under which there is a UsersController (/admin/users/:id) and as a sub-resource of users, we have a UserOverride resource (/admin/users/:user_id/override)... it feels really logical that we just POST and DELETE to this resource.
So getting back to your example, yes, I think you should break those sections down into separate resources. It certainly seems like BookContent should be a sub-resource of Book, and MarketingOptions too.
resources :books do
resource :content
resources :marketing_options
end
etc
This is both nicer to work with (more modular) and easier to visualize just from looking at the routes alone. You also get the benefit of really predictable path helpers:
<%= link_to("Marketing Options", book_marketing_options_path(#book)) %>
You can't try to force every conceivable route into a RESTful resource ideology though... if it feels like it's forced, then it probably is.
There's a decent blog post I wanted to link to that (despite some poor grammar) actually does a pretty good job of showing you how to think about your application in terms of resources... I can't find it though. I'll add a comment if/when I do.
EDIT | Just re-reading your original question and wanted to clarify: resource != row in database. A resource is anything you can conceive as a "thing"... I know that's a very broad statement, but just like an Object in OOP doesn't have to represent something concrete/material, nor does a resource in a RESTful design.
I'm having a bit of difficulty coming up with the right answer to this, so I will solicit my problem here. I'm working on a RESTFul API. Naturally, I have multiple resources, some of which consist of parent to child relationships, some of which are stand alone resources. Where I'm having a bit of difficulty is figuring out how to make things easier for the folks who will be building clients against my API.
The situation is this. Hypothetically I have a 'Street' resource. Each street has multiple homes. So Street :has_many to Homes and Homes :belongs_to Street. If a user wants to request an HTTP GET on a specific home resource, the following should work:
http://mymap/streets/5/homes/10
That allows a user to get information for a home with the id 10. Straight forward. My question is, am I breaking the rules of the book by giving the user access to:
http://mymap/homes/10
Technically that home resource exists on its own without the street. It makes sense that it exists as its own entity without an encapsulating street, even though business logic says otherwise.
What's the best way to handle this?
EDIT! In spirit of becoming a good StackOverflow citizen, I've come back with a supported code block for how to implement they above.
map.resources :streets,
:has_many => :homes
:shallow => true
This will create both types of routes that I was looking for.
If your Home records can only belong to one Street, then the relationship won't be confused when you're examining a Home individually. You'll still be able to back-track to the associated Street record for whatever reason.
It's in situations where you have a many-to-many relationship that de-nesting your REST structure can get you into trouble. If a particular record only makes sense in a particular context, and you remove that context, obviously there is confusion.
I think in your particular case you may not need to implement both approaches, but instead go with the "flatter" approach that reduces the complexity of the URL.
Nope, that is how shallow routes work and are used a lot.
I really like this approach. I recomend to read it. In short this article says that you shouldn't nest your resources more then 1 level. And if it is possible that nested resource can be shallowed, then do it.
In one of my applications I really messed things up with nested resources. I go even to 3 or 4 deep and it become a nightmare...
Nesting is really nice if it makes things simpler. If not, give it up!