Jaskaran
Jaskaran

Reputation: 188

When the form is submitted with an error, the rendered url changes in Rails 4

I have created a user signup page. When the user submits the form incorrectly, when displaying a validation error, it does not render on the same URL.

The signup form is located at this url:

http://localhost:3000/signup

I have added the following routes for the signup page:

resources :users
match '/signup',  to: 'users#new', via: 'get'

When I submit the form, the model validation shows up but the url redirects to:

http://localhost:3000/users

I want the user to remain at the same url after submitting the form.

http://localhost:3000/signup

This is my controller code:

def new
    @user = User.new
  end

  def create

    @user = User.new(user_params) # Not the final implementation!

    if @user.save
      # Handle a successful save.
    else
        render 'new'
    end
  end

This is the beginning tag of my form:

<%= form_for @user, url: {action: "create"}  do |f| %>

Upvotes: 6

Views: 1791

Answers (2)

Taylor Liss
Taylor Liss

Reputation: 593

I believe that @Jaskaran's question is in regards to question 2 found at the bottom of Michael Hartle's Ruby on Rails Tutorial, section 7.3.3, so I will be answering in reference to that question:

  1. How does the URL on the unsubmitted signup form (Figure 7.12) compare to the URL for a submitted signup form (Figure 7.18)? Why don’t they match?

To answer this question, we need to understand how routing works in a Rails application. Let's walk through what happens when you visit each page and make a submission.

Your main page (home.html.erb) contains a link to your signup page (new.html.erb). That link looks like this:

<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>

The signup_path is the part we are most interested in. signup_path is a route helper and essentially tells Rails that when someone clicks on that link, Rails should behave as if they just went to your /signup page. This is why the first URL you see (before submitting the form) shows http://localhost:3000/signup.

Now let's take a look at what happens when your form is submitted. According to the new.html.erb file, the form is contained within this Ruby code:

<%= form_for(@user) do |f| %>
. . .
<% end %>

You may remember from 7.2.2 that that Ruby code is actually rendered in HTML as:

<form class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
. . .
</form>

What that is saying is that when the form is submitted, it will make a POST request to /users - and that's the URL that you are seeing in your browser.

We can better understand why this is if we first stop to think - where does /users route to? You can quickly check your routes by typing bundle exec rake routes in your console. You should see it listed there:

Prefix Verb   URI Pattern               Controller#Action
users  GET    /users(.:format)          users#index
       POST   /users(.:format)          users#create

So any POST requests to /users will be routed to the create method of our users_controller.rb. If you're wondering why that is, it is because we added this line to our routes.rb file:

resources :users

More details on that line can be found here.

Upvotes: 2

solstice333
solstice333

Reputation: 3649

I'm working with Rails 5, but I suspect it's not too different conceptually.

In routes.rb:

get 'signup', to: 'users#new'
post 'signup', to: 'users#create'
resources :users

and in your form helper:

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

Essentially, the reason why it's not working as described in your original post is because when the form posts (rails 4.2 form helpers), it's tied to url: {action: "create"}, which by default, according to the routes automatically generated for resources :users, is post '/users', to: 'users#create (rails 4.2 routing guide). And by searching top down in routes.rb, it'll see this first and you end up with http://localhost:3000/users.

So, the changes I propose, should bind the form to post to the signup path instead which, in routes.rb, is seen as the second route entry.

Upvotes: 5

Related Questions