basic routing question with HABTM

Hi, Rails newbie here.

If I have a basic HABTM association - say, users and groups - I can't
get my head around the RESTful routing required to add a user to a

POST /user will call user#create
POST /group will call group#create
POST /group/:group_id/user should call: what? Is it ok to define
a "addUser" action to the group controller? Or should I test for the
existence of the group_id in the user#create method and then proceed
accordingly? I want to do things the Rails way but sometimes my PHP
experience comes back to haunt me. :slight_smile:



I’m not sure what do you mean… but maybe this sample code will help you… :slight_smile:

resources :groups do

resources :users # using nested routes :slight_smile:


It will generate url like this

new_group_user GET /groups/:group_id/users/new(.:format) {:action=>“new”, :controller=>“users”}

You can see the detail with “rake routes”



Thanks for responding, but that's not really what I was looking
for. My basic problem is that I don't understand how to correctly
distinguish between user creation and assignment of a user to a group
using RESTFUL routes. It appears to me that with nested routes, you
end up with users#create in both cases.


There is no one 'correct' way to do this. Both of your suggestions will work. But I'd agree with your instinct that they both feel a little bit hackish.

One solution would be to specify a different controller to handle users scoped inside groups:

resources :groups do
  resources :users, :controller => 'group_users'

Then the concept of creating a user inside a group, and the concept of creating a user, can be handled in completely separate controllers.

The problem with this is that you'll be passing parameters like :user => {:name => "Bob Smith", :email => "", …} to your UsersController, while passing parameters like :user_id => 2 to your GroupUsersController. It feels like theres some inconsistency there.

So you could invent a new concept, called a 'membership':

resources :groups do
  resources :memberships

When a user joins a group, you're not really creating a user -- you're creating a membership. When a user leaves a group, you're not really deleting a user -- you're deleting a membership.

Note that a resource doesn't have to match one-to-one with a database-backed model. So you can expose this concept of a membership at your controller level, and let the controllers deal with converting that to model talk:

POST '/groups/1/memberships', {:membership => {:user_id => 2}}

class MembershipsController < ActionController::Base
  def create
    @group = Group.find(params[:group_id])
    @user = User.find(params[:membership][:user_id])
    @group.users << @user
    redirect_to wherever

Like I say, there isn't a 'correct' way of handling this kind of thing, but I personally like the idea of exposing the semantics of your application like this, and trying to think of things in terms of CRUD where possible.