Those look like legitimate bugs in implementation, rather than caused
by confusion. I don't really see a point in extracting that
functionality in a plugin, with hope of making a come back to core. If
it's gets converted into a plugin, it should stay there, always.
Also, converting an edge functionality into a plugin because of
defects in implementation, defeats the whole purpose of having edge at
first place. I guess it's time to make a choice once and for all, if
it's gonna be in core rails or not.
My vote is to keep it in edge for points explained in posts above.
You identify the join with the id of the join model. Thats the purpose
of using has many though, exposing an actual model. If you could
pastie on example, I could show you how to model it better.
"/companies/1/people/1" == BAD
"/people/1" == GOOD
I have no problem with nested collections.
"/companies/1/people"
You shouldn't need to be scoping person #1 if its the unique id.
But isn't that the rub? Who says the ids must be unique? True, Rails
support for composite keys makes it less-than-direct to convert the
REST resource with composite keys into an AR model with unique keys,
but from a UI point of view, some may just want to expose more
intuitive composite keys:
The path components really are part of the UI -and sometimes a very
visible part. I want mine to be intuitive and that sometimes means
nested with non-unique IDs.
In all of those URLs it is very clear which single resource we are
referencing: Child 234. But the URLs give very different context
information. For the first URL, I want to show a pink background, in
the second I want to show a blue background and in the last one, I
want to show a white background, to give a simple example.
Context counts.
Now if we could only get Rails to help us identify that context more
accurately, I'd be happy [warning -going slightly off topic...].
Are these two URLs presenting the same context?
/users/17/groups/2/tags
/groups/2/users/17/tags
Short of routing these URLs to different (otherwise identical)
controllers or manually inspecting the URI, does anybody know how to
differentiate them?
Sure would be nice if Rails exposed the matched route to the
controller! Perhaps an RO attribute of
ActionController::AbstractRequest set in
ActionController::Routing::RouteSet.recognize?
No, it doesn't suck at all, and that snippet represents a Rails "best
practice", doesn't it?
Frankly, I haven't seen any compelling arguments against multi-level
nested routes yet. Not to mention that If you have public-facing URLs,
then the realities of SEO mean that the more relevant information you
can cram into your URLs the better.
It’s getting quite large. I’ve included relevant models, controllers and views, limited to an example of the purpose at hand. The index view of the clips controller.
The only time I access clips via a nested route is by the ClipsController - index, and show methods. Other than that I don’t require the nested resources at the moment.
I’m actually very apprehensive about putting this out for public crit, but I’m more interested in how to model this properly for this project and future ones, so please be gentle There are some very messy parts in the user model associations to access clips. The funny thing is, for all the ugliness they provide, I’m not actually using the methods anywhere yet.
If I’ve left out any important aspects of the code let me know.
doesn't reveal whether the underlying association between Album and
Track is has-many, has-and-belongs-to-many, or has-and-belongs-to-many-
through. I see this as an asset -- you can refactor your model
associations as business requirements change without having to rework
your uri structure.
2) even if you do have a join table -- say Book
has_many :authors, :through => :authorships -- you still might want
the uri to reference a Book and an Author, which are concrete objects.
rather than an Authorship, which is an abstract concept. In the real-
world DSL of the book trade, a customer might request more information
about a book's author, or about a particular book written by an
author, but not for more information about an "authorship."
Not at all. The alternative implies: If you go around promoting every
2-way association (habtm) to an actual Entity, you probably want to
crack open the PoEAA and brush up a bit on Domain Model. Your object
model can be richer than your database schema. That's not a bad thing.
Trying to achieve 1:1 parity between the two seems awfully misguided.
More than that, a single authoritative URI for a particular resource
seems arbitrarily limiting. Objects don't work that way (see:
references). Your database schema doesn't work that way. What goal is
being achieved through it? Nothing at all pragmatic as far as I can
tell...
In fact, the idea that 2-way associations should be banished from your
Domain Model is entirely unique to Rails as far as my limited
experience suggests, and it certainly doesn't strike me as a good idea
at all, but more a misrepresentation of "you can" into "you should". I
might even go so far as to call the unjustified and/or indescriminate
promotion of habtm relationships to has_many => :through as a "code
smell", though I personally can't stand the phrase.
You are assuming that you know what the route will be. When developing a controller to handle a polymorphic resource its quite often that you don’t know the type of the objects, thus polymorphic_path([@parent, @child]) becomes much cleaner then a nested if or case statement.
I am actively using this feature on two large scale applications which are deployed into production and it has helped me to maintain skinny polymorphic controllers.
I'm having a really hard time wrapping my mind around the nesting,
except that the URL looks pretty. Do you really mean to say that we
should be accessing both objects that way? It seems really hackish.
When I did this without nested routes on my first project, I built
URLs this way but never used the post_id in the URL at all. Is that
wrong?
I'm just looking for some enlightenment here, not trying to be
difficult!
This is for security/data integrity reasons. When you fetch like the
example above, you can only access posts that were written by the
user. And only access comments written about that particular post. On
a blog that might not matter much, but on an application that keeps
data secret from different accounts, it's paramount.
Some people use the concept of resource nesting or "belongs to" to
manage security, but it is pretty one-dimensional. More robust
security systems (role-based access control, for example) have a much
richer concept of authorization than could possibly be expressed in a
request string. I love nested resources and use them a lot, but I
wouldn't have expected Rails to hold up one (simple) interpretation of
security as a justification.
I justify nested resources because they provide context information.
For example:
/users/23/groups/17/tags
/groups/17/users/23/tags
Those two URLs refer to very different things and it is the ORDERED
nesting that sets them apart. Unfortunately, Rails doesn't provide
any help with the ordering (ticket 8105) obliging me to inspect the
request in order to know which tags we are talking about.
That just really seems to get messy. Is that really the approach you’d take? I assume you’d use some sort of includes there to reduce the db calls then, right?
Are there examples of projects that use this nesting stuff in the wild that we could actually see the code to? I’d love to figure out what I’m missing here, as I really feel like I’m not “getting” it. In the past, for security purposes, I’d just have the user own everything by user_id and use that to see if someone can actually use it.
Thanks for the explanation though, this is a really good topic.
Are there examples of projects that use this nesting stuff in the wild that
we could actually see the code to? I'd love to figure out what I'm missing
here, as I really feel like I'm not "getting" it. In the past, for security
purposes, I'd just have the user *own* everything by user_id and use that to
see if someone can actually use it.
But if you have a team of people who can access a project, then how
can you use user_id?
I'd expect almost all of the open source rails applications which do
this kind of security will be following association proxies to
implement their security.
AIUI, In this situation, I'd be in the notes_controller. I'd have already set up find_user, find_project, find_task, and find_note_by_id methods called by before_filter, e.g.,
# in application.rb
private
def find_user
@user = User.find(params[:user_id])
end
def find_project
@project = @user.projects.find(params[:project_id])
end
def find_task
@task = @project.tasks.find(params[:task_id])
end
Sure. Very much so… and that’s exactly how I’ve been doing it. So what I understand is that it’s perfectly fine to query the database that many times, because it’s good for security and data integrity. I can live with that. Just wanted to make sure that was the best way to explain it to my students. Some people will surely look at the sql logs and see four separate (albeit small) queries and wonder why that’s necessary, so I want to have a good answer for them.