thoughtbot/guides

Why "avoid member and collection routes"?

radar opened this issue · 3 comments

radar commented

This repo was linked to on #RubyOnRails on Freenode today (link).

I'd like to know the reasoning behind avoiding member and collection routes. I personally currently have an InvitationsController which sends out invitations to users and they have to accept them. I therefore have a member route for the accept action in that controller.

I'd like to know the Thoughtbot's team's reasoning for this statement and what you do instead.

I can only speak for myself, but I've found time and again that extracting named resources for these types of things clarifies thinking around them and leads to better design. That's not a certainty in all cases, but it's worked enough for me that I'm willing to push back hard against member routes.

In your specific example, I'd consider:

resources :invitations, only: [:new, :create, :show] do
  resource :acceptance, only: [:create]
  resource :rejection, only: [:create]
end

The advantage of this approach that I've seen born out in several applications is that it it encourages thinking of the acceptance and rejection as processes that involve an invitation but not necessarily methods on an invitation. If accepting or rejecting an invitation has side effects it's less tempting to lump them into the InvitationsController (where they have very little to do with other actions in that controller) or Invitation itself (where it may involve additional collaborators).

Maybe acceptance and rejection are simple actions right now that just set a flag in the database. In that case, perhaps the member route is fine for you. I've just seen it slide downhill into bad territory enough that I'd prefer to make the tradeoff early to encourage what I would consider better behavior if or when those get more complicated.

As a side benefit, I also find reviewing routers where everything is, as much as possible, expressed as resources to be more enjoyable. The router is where I first head when coming on to an existing application and I find that when things are expressed strictly in terms of resources it's easier for me to get a quick overview of the objects at play and the actions that can be performed on them.

As with all of our guides, these aren't hard and fast rules. Avoid means "don't do it unless you have a good reason". A reason is good when you can convince a teammate. I tend to hold firm on this, but I know others here feel less strongly about it.

I agree with everything @derekprior said.

Also, I really enjoy the absolute predictability of routes/controllers/actions/helpers/etc when the standard seven actions are used. There's very little reason in Rails to avoid creating a new controller for actions like these, so I think the predictable routes are well worth it. In an application that follows these conventions, I know exactly which controller to jump to if I want to know what's happening at a certain URL or what will happen when I click on a link using a particular route helper method. Without these conventions, you need to scan several files (or run rake routes) to piece together the various parts of routing.

I'm going to close this issue, as it's not a bug or something that needs addressing. However, please feel free to continue to discuss or ask questions.

radar commented

Great explanation. Thanks Derek + Joe :)