Why is "render 'new' " changing my URL? (Ruby On Rails)

The reason the URL shows /clients after submitting invalid data is because the /clients/new form submits the request to clients#create which is registered under POST /clients if you use the Rails defaults.

If your data was valid, Rails will redirect the user to the root path GET /. If your data was invalid it will render :new as response to POST /clients which shows up as /clients in your browser.

If you try to refresh the page after submitting invalid data, the browser should ask something like "do you want to resubmit the form?". If you click yes the page is refreshed and and it shouldn't hit GET /clients (which normally routes to clients#index). If you manually click in the URL bar of your web-browser and hit Enter a GET /clients request is send instead, thus landing you on the wrong page.

You can see all routes, including request types, by running the rails routes command.


Your expectation is completely wrong but quite common among Rails beginners.

In Rails flavor REST GET /clients/new is just a page that contains the form for creating a new resource. Since its a GET request it is idempotent - that means its stateless and looks the same for all visitors.

When you submit the form your browser is sending a POST request to /clients. Again in Rails flavored REST this is how you create a resource.

If the validation fails rails simply renders a response containing the form. This SHOULD NOT redirect the user as what you are seeing is the result of the non-idempotent POST request. This is not the same resource as GET /clients/new.

In fact render 'new' is just a shortcut to render 'app/views/clients/new.html.erb'. The two endpoints share a view - nothing else.

Why is that? Isn't "render" supposed to not change anything from the URL?

You are completely mistaken. render does not change the URL. Submitting the form earlier changed the URL in the browser. Render just renders the view and returns it as the body of the response. Look at the logs of your Rails app if you want to get an idea of how the interchange between client and server actually works.

You can contrast this with redirect_to which sends a location header back and the correct response code (302) which will redirect the browser to the new location.

This gives problems when I refresh the page because I have no "index" view and it's triggering an error instead of showing the "new" view as it's supposed to.

To resolve this you need to add an index action which can be a simple redirect to /clients/new. When you reload the page you are sending a GET request to /clients which should render the index.

I would really recommend that you try just creating a scaffolded rails app so that you get an idea of how the rails conventions do simple CRUD operations before you start imposing your own ideas.


When you submit this form, it goes to /client URL with the post method. And when you call render method in case of error, let's understand how 'render' works and what it does (and how it is different from 'redirect'):

render: Renders the content that will be returned to the browser as the response body.

Render tells Rails which view or asset to show a user, without losing access to any variables defined in the controller action.

Redirect is different. The redirect_to method tells your browser to send a request to another URL. Since the request is completely different, the view to which you redirect will NOT have access to any variables defined in the controller.

So in this case, if you redirect, you will lose your submitted data as this will be a completely fresh and independent request.

There are some ways (described in below URL) by which you can also change the URL with render (but these are not the Rails and Rest way.)

Render template and change url string in browser?