I would use a specific controller. Even if now the interaction sounds simple, you can't know if in the future you'll need to add more advanced features.
I've been handling these kind of relationships in several projects, and using a controller for the join model has always paid off.
You can structure it this way, for example:
index
should expect aparams[:project_id]
, so that you can display only the index of users for a specific project.create
is where you add new users, that is where you create new join models.update
is to modify a value on an existing join model, for example when you want to update the role of a user in a project.destroy
is where you remove users from the project, that is where you delete the corresponding join models.- You might not need a
show
andedit
actions, if you decide to manage everything in theindex
view.
Also, I'd suggest to choose a different name. Rails relies heavily on naming conventions, and projects_users
is the default name for the join_table you would use with a has_and_belongs_to_many
association. In theory you can use it for an independent model (and a has_many through:
), but it's not immediately clear and you might break something. In addiction, it will confuse the hell out of any new programmer that could join the project in the future (personal experience).
What about calling the model something like project_participation
?
If you haven't built a lot of functionality yet, and don't have yet that table in production, changing it now will save you a lot of headaches in the future.
update
1) I stand by what I said earlier: your join model is a full fledged record, it holds state, can be fetched, modified (by the user) and destroyed.
A dedicated controller is the way to go. Also, this controller should handle all the operations that modify the join model, that is that alter its properties.
2) You can define User#role_for(project)
, just remember that it should properly handle the situation where the user
is not participating to the project
.
You can also make it explicit with something like:
@user.project_participations.where(project_id: @project.id).first.try(:role)
# or...
ProjectParticipation.find_by(project_id: @project.id, user_id: @user.id).try(:role)
But I'd say that encapsulating this logic in a method (on one of the two models) would be better.
3) You are already using a non standard name for your table. What I mean is that it's the default name for a different kind of association (has_and_belongs_to_many
), not the one you are using (has_many through:
).
Ask yourself this: is the table backing an actual model? If yes, that model represents something in the real world, and thus should have an appropriate name. If, on the other hand, the table is not backing a model (e.g. it's a join table), then you should combine the names of the tables (models) it's joining.