RESTful resouces & many-many 2: more complicated

Subscribe to RESTful resouces & many-many 2: more complicated 14 posts, 2 voices

 
Avatar jcoffman 19 posts

I was hoping the earlier thread on REST and many-many would be the answer I was looking for, but it didn’t quite address my situation. (Or I’m just dense) I have a many to many with a twist.

The main models are Company, Project, and Approver (one who approves project activities)

Goes like this:

Company has many Project and Approver

Approver belongs to Company

Project belongs to Company

There will be a many-many relationship between project and approver. When the user creates/edits a project, he can pick the company it belongs to. Based on that he should be able to select which approvers are assigned to that project. So there is a many to many between Project and Approver, but is dependent on an editable project attribute of company_id.

I’ve called the many-many model: ProjectApprover (creative, huh?) So we also have this meta:

ProjectApprover belongs to Project and Approver

Project has many Approver thru ProjectApprover

Approver has many Project thru ProjectApprover

How in the world do I make this RESTful? Remember, the user picks the project’s company and then picks the approvers for that project based on the selected company.

thanks -j

 
Avatar jcoffman 19 posts

I know it’s not a standard REST method (not one of the magic 7), but would a url like this be considered RESTful:

/projectapprovers/99/list_by_company

or

/projects/99/list_by_company

The “99” in the above url’s being the company_id; the output rendering the list of approvers for that company. I dunno but it doesn’t seem clear or well-related to the resource in either URL. The end user won’t see this url in their browser, but I’m trying to stick with a consistent methodology.

 
Avatar Jeff Cohen 89 posts

I almost understand :-)

Are approvers related to companies in any way?

 
Avatar jcoffman 19 posts

Yeah, Approvers belong to companies.

ie:

class Company
  has_many: Approver
  has_many: Project
end class
class Approver
  belongs_to: Company #table has company_id attribute
  has_many: Project; though: ProjectApprover
end class
class Project
  belongs_to: Company #table has company_id attribute
  has_many: Approver; though: ProjectApprover
end class
class ProjectApprover
  belongs_to: Project
  belongs_to: Approver
end class

Is that clearer? I think the tricky part is that a user can edit the Project and change the company it belongs to. Based on that, they need to be able to select Approvers for that project. (weird, I know)

 
Avatar Jeff Cohen 89 posts

Sorry, one more question. Must the approver’s company always be the same as the project’s company? So a project for Apple can only have approvers that also are associated to Apple? Or, can approver1 work for Apple, and be an approver for a project belonging to Microsoft?

 
Avatar jcoffman 19 posts

its restricted so approvers must belong to the same company as the project. I figured I would handle that in code; which means if they change company, I’ll need to make sure I remove approvers that don’t belong. That’s an old problem that i’ve handle a lot in vb & .net.

clarifying…. What throws me off about this is REST. I am not strong enough with it (or ruby/rails) to know how to handle. If I throw REST out the window, I can handle this. I’d really like to learn and grow and stick with REST.

 
Avatar jcoffman 19 posts

I’ve thought about this some more. In order to keep it RESTful, I need a new controller for fetching the list of Approvers by company. I just don’t know how to name it without using a verb word in the controller name. Maybe CompanyProjectApprover?

 
Avatar jcoffman 19 posts

I decided to try a custom route as in this railscast: http://railscasts.com/episodes/35

Only I’m getting an error trying to use the named path because it is confused between that and the Show request; both are GETS. Anyway, I’m thinking the custom routes stuff has changed since this railscast.

 
Avatar Jeff Cohen 89 posts

I’m sure I’m not grasping all the details of your situation, but it seems like you have a nested resource here. Something like

@projects/5/approvers

should return a list of approvers for project #5. Two keys here: one is to setup your routes.rb like this (I’m assuming you’re on Rails 2.x):

map.resources :projects, :has_many => :projects

and then in your ApproversController, a before_filter to get the project:

before_filter :find_project

def index
  # Show list of approvers for the current project
  @approvers = @project.approvers
end

private 

def find_project
  @project = Project.find(params[:project_id])
end

This might not be exactly right, but hopefully this points to a more helpful direction?

 
Avatar jcoffman 19 posts

Close enough… I’ll try to use it as a nested resource. /projects/5/approvers is valid ..sort of.. When editing/creating a project, the user picks the company it belongs to. The app then updates/populates the available choices for approvers that belong to the selected company. Lastly, the user can pick which approvers have authority on that project. I’m probably just bad at explaining this.

I think I can bend the nested resource approach to fit my needs. Thanks.

 
Avatar Jeff Cohen 89 posts

Any chance you can change the user interaction at all?

I would have guessed that you’d start from a Company page, then create New Project or something. So right from the get go, you know what company is involved, and that makes creating the drop-down lists much easier.

In any event, let me know how it all turns out! As long as you can somehow thing of (most) everything in terms of crudding a resource, I think things will still work out.

 
Avatar jcoffman 19 posts

hmm… I could probably change to create the project from the company. I hadn’t thought of it in that way. It would simplify my problem.. and possibly also simplify the UI. I could do the same thing for Approvers also since they too belong to a company.

Those would then make sense as nested resource on Companies, which is not a bad idea..

map.resources :companies, :member => { :enable => :put } do |companies|
  companies.resource :approver
  companies.resource :project
end

I’m not exactly sure about the implementation after that but the resource and url of that makes sense to me. I’m gonna guess I need to use that before_filter approach you mentioned above.

 
Avatar jcoffman 19 posts

UPDATE: I did what I said last, which was to make approvers and projects nested resources on companies. It works and I’m quite happy with it. It simplified a couple things. I also changed from has_many+through to HABTM. Its RESTful and I think the user interaction will make more sense too.

Thanks Jeff.

 
Avatar Jeff Cohen 89 posts

Awesome! Way to persevere through it! I hope it works out.