3

Okay, so here's an example scenario. There is a student resource resources :students, and students has and belongs to many collections: resources :clubs, resources :majors, etc.

So we can set up our routes easily enough...

resources :clubs do
  resources :students
end
resources :majors do
  resources :students
end
resources :students do
  resources :clubs
  resources :majors
end

which generates us a bunch of standard RESTful routes

  • /clubs
  • /clubs/:id
  • /clubs/:club_id/students
  • /clubs/:club_id/students/:id
  • /majors
  • /majors/:id
  • /majors/:major_id/students
  • /majors/:major_id/students/:id
  • /students
  • /students/:id
  • /students/:student_id/clubs
  • /students/:student_id/clubs/:id
  • /students/:student_id/majors
  • /students/:student_id/majors/:id

So here's my question. With REST semantics, how would one delete a major for a student? Browsing students under a major /majors/:major_id/students/:id would show that student in the specific major's 'collection'. But the route for deleting an :id, points to StudentsController#destroy, which would delete the student completely. Whoops! So maybe we go the other way, and perform DELETE on the resource at /students/:student_id/majors/:id and well now UnderwaterBasketweaving is now no longer offered at this school...Whoops!

Now granted, we could set the destroy method of ClubsController, MajorsController, or StudentsController to look for club_id, or major_id, or student_id, but lets say we also down the road want to add Fraternities and GraduatingClasses, etc. Each class would start to be comprised of huge switch conditionals looking to see what param was present... and then find the collection of either the top resource and remove the bottom resource, or vise versa. The Models themselves should decide whether they delete themselves if they have no more association records... 'Destroy' on that resource has become really a misnomer...

Is there an easier way to do this? Even popular restful rails plugins like make_resourceful or resource_controller would blow away UnderwaterBasketweaving when removing it from Joe's Majors or completely delete JohnDoe when removing him from the major UnderwaterBasketweaving. It would seem there's a potential for looking at the association to understand the desired effects of the semantics and what 'destroy' should do.

Then again, am I looking at this all wrong? Is it not UnderwaterBasketweaving -> Joe but UnderwaterBasketweaving+Joe as a single resource and what we're deleting is truly not Joe, nor UnderwaterBasketweaving, but the resource representing the combination? However, that's not easy when the controllers are Students and Majors, that in effect represent resources of the same name (MVC has really become RV...in the 'convention' approach and not developing Controllers that may have no bearing on a Model name, or the path to reach it) So you'd be deleting a Major or a Student; pick your poison...

How can I avoid managing conditionals across an infinite graph of associated resources where delete really isn't the intent when the delete is desired to be in context of a collection and not pertaining to its singularity...?

...major.student.delete... Is there a way for 'student' ActiveRecord object to know it was sent a 'delete' message in a method chain beginning with the 'major' AR object ?

1 Answer 1

2

Well the standard RESTful aproach is to use has_many :through and generate a cotroller for the association resource. Naming association resources is always difficult, but I'll attempt for this example.

resources :majors do
  resources :studies
  resources :students
end
resources :students do
  resources :studies
  resources :majors
end

The models would be of course:

class Major < ActiverRecord::Base
  has_many :studies
  has_many :students, :through => :studies
end

etc. (comment if you want me to elaborate)

Then for a student you wouldn't DELETE it's associated @student.major but his @student.studies.where :major => @major.

Sign up to request clarification or add additional context in comments.

4 Comments

I think I like this approach, except for the sheer volume it could cause of excess code. Outside of my contrived example, I'd have over 100 association resources in my actual project. It seems that we're breaking the C over C paradigm here by configuring a lot of extra code where the ideas are already there in the original association code (not using :through); though the reason some of the restful plugins like make_resourceful are nice is that they move the relationship semantics into the controller space so that this would be more feasible to logically process into meta-generated code
Also, you wouldnt have resources :majors having many :students since its not a nested resource under your paradigm (as I'm following...). The nested resource to each is the association resource, which definitely solves the problem of deleting the wrong object. The association resource could then have nested resources of what it relates to which are the true domain models. Again, I love it, though worry about the excessive association resources to manage. Its interesting that weve gone from hierarchical taxonomy into promoting multi-faceted ones, yet (RESTful) URL is still very hierarchical
I'm not sure I follow your second comment. Generally spoken has_many :through behaves exactly like has_and_belongs_to_many except that it gives you control over the association. So you will need to generate the models for those associations. However you can restfully manage their creation and deletion in other controllers. See accepts_nested_attributes_for. Controller plugins are nice (I personally use InheritedResources, but for many cases you'll have to write the code yourself (or write a library that solves your particular use case).
(It'd be nice if comments on here were threaded (reason blog swapped in solutions like IntenseDebate|Discus)) I just meant that while the Models are nested, the Resources aren't particularly. Your answer works because it breaks my prior mindset of 1:1 of models<->resources. The 'controller' really is the Resource, which can implement an abstraction (e.g. 'studies'), which I guess then wouldn't even need to be a has_many :through (usually a habtm where you need to have domain logic on the association; in this case we just need to represent that association, but it has no logic per se)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.