Pierre P.
Pierre P.

Reputation: 1065

Rendering 'new' leads to a different url

When handling validation errors in a User form on my rails project, I have the instruction render 'new' if the user is not valid.

However, when this occurs, the url in the search bar changes.

Originally, it's https://localhost:3000/signup but when the user submit the forms and the render 'new' occurs, the URL becomes https://localhost:3000/users

Why is that?

Here's my routes.rb

Rails.application.routes.draw do

  # Resources
  resources  :users, only: [ :new, :create ]

  # Application root
  root 'static_pages#home'

  # Static pages
  get '/help', to: 'static_pages#help'
  get '/contact', to: 'static_pages#contact'

  # Users
  get '/signup', to: 'users#new'

  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

Thanks,

Upvotes: 0

Views: 940

Answers (5)

max
max

Reputation: 102001

In the Rails REST conventions you use different URI's to display the form to create a resource and for the forms action attribute which you POST to.

Lets say you have:

resources :pets

This gives us:

GET  /pets/new  => pets#new
POST /pets      => pets#create

We then have a typical form:

# posts to /pets
<%= form_for(@pet) do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>

And a run of the mill controller:

class PetsController < ApplicationController
  def new
    @pet = Pet.new
  end

  def create
    @pet = Pet.new(pet_params)
    if @pet.save
      redirect_to @pet
    else
      render :new
    end
  end

  # ...
end

So when the user visits /pets/new and fills in the form the browser url should read /pets if the form is invalid. This is the intended behavior - posting to a different URL avoids a myriad of cache and history related issues.

From a restful standpoint its also correct - you're no longer viewing the new action - you're viewing the results of attempting to create a resource. The former is idempotent - the latter is not.

You need to recognize that the line render :new is short for render template: 'pets/new'. It does not redirect and it does not call the new action in the controller. It simply renders the template and returns it as the response to the current request.

Upvotes: 2

Timmy Von Heiss
Timmy Von Heiss

Reputation: 2218

You need to add

post '/signup', to: 'users#new'

Upvotes: 0

Mark
Mark

Reputation: 10998

The reason for this is because when you submit your form, you're submitting it to some action from your new view. The action that the form submits to has a path, and you can see what the path is by typing:

rake routes

in your console and searching for the create action. When your validation fails in the create action, you call render 'new'.

When you render a template, the url of the page being rendered will be the url / path of the controller action that rendered the template.

In your case, whatever action you have that calls render 'new' will be the one determing the url once your template is rendered.

Upvotes: 0

Ryenski
Ryenski

Reputation: 9692

The reason this is happening is because of the way Rails handles routes. Most likely, the form on your signup page has something like:

<?= form_for @user do |f| ?>

If you look at the generated HTML you'll notice that the form is POSTing to the url '/users'. So when the signup form is submitted, the app is going to redirect you to /users.

This is the normal behavior in Rails. (see Rails Guides)

If you want the URL to look like /signup you can add a named route for it:

# Users
get '/signup', to: 'lead_magnets#new'
post '/signup', to: 'lead_magnets#create'

Then in your signup form you'll need to explicitly reference the new signup path:

<?= form_for @user, url: signup_path do |f| ?>

The generated HTML should look like

<form class="new_user" id="new_user" action="/signup" method="post">

Upvotes: 1

Adrianopolis
Adrianopolis

Reputation: 1292

Did you try to include recognize path?

Rails.application.routes.recognize_path

Upvotes: 0

Related Questions