New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why "avoid member and collection routes"? #401

Closed
radar opened this Issue Feb 8, 2016 · 3 comments

Comments

Projects
None yet
3 participants
@radar

radar commented Feb 8, 2016

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.

@derekprior

This comment has been minimized.

Show comment
Hide comment
@derekprior

derekprior Feb 8, 2016

Contributor

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.

Contributor

derekprior commented Feb 8, 2016

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.

@jferris

This comment has been minimized.

Show comment
Hide comment
@jferris

jferris Feb 8, 2016

Member

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.

Member

jferris commented Feb 8, 2016

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.

@jferris jferris closed this Feb 8, 2016

@radar

This comment has been minimized.

Show comment
Hide comment
@radar

radar Feb 9, 2016

Great explanation. Thanks Derek + Joe :)

radar commented Feb 9, 2016

Great explanation. Thanks Derek + Joe :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment