Search code examples
ruby-on-railspostroutesputrestful-architecture

Rails: Why does create/update action point to the same URL like the index action?


When creating or updating a resource, the target URL by default is the same like the index route, for users e.g. localhost:3000/users.

The difference is that instead of POST, PUT method is used (as far as I know).

I find this suboptimal. For example, when having a navigation menu with an item "Create user" in it, I want to set the active CSS class when the item is active. I do this by comparing current_page? to the menu item's URL (e.g. users/new). This works fine, but only when I don't have validation errors. In this case, the URL now isn't users/new anymore, but users.

Is there a good reason why Rails doesn't point to users/new (or users/edit) respectively for POST/PUT requests? Are there any downsides to using them? Is there an easy way to change this behaviour?


Solution

  • The reason is REST.

    In a nutshell, Rails treats everything as a resource, and there are conventions followed in order to do so. In a typical CRUD application, you have the Create (POST), Read (GET), Update (PUT/PATCH), and Destroy (DELETE) actions, which are the verbs used to act on resources.

    Let's say you have a User resource. A list of users would be found at /users. An individual user, being an individual object of a resource, would then be found at /users/1, where "1" is the identifier of the resource in question.

    Now, based on the CRUD verbs available to you, if you wanted to edit a user, what ACTION makes the most sense given the CRUD verbs we talked about? PUT /users/1 is the correct answer; you're updating (the U in CRUD) a particular resource. If you wanted to delete that user? DELETE /users/1 makes sense. If you want to create one? CREATE /users is the logical choice, because you're not acting on a particular object, but on the resource as a whole, similar to GET /users not acting on an individual object, but a collection.

    /users/new is a path to a page that will let you do that, but it doesn't mean it should make the CREATE request to /users/new, because "new" doesn't describe a resource the same way.