apardes
apardes

Reputation: 4380

Ruby on Rails Routes Clarification

I'm not completely new to Ruby on Rails but it is not my most proficient framework so I was hoping someone could help me wrap my head around some code I'm trying to understand.

controller:

def new
    @biz = Business.new
end

def apply
    @biz = Business.new(business_params)
    token = SecureRandom.hex(4)
    @biz.verify_token = token
    if @biz.save
        message = @biz.sentMessages.new
        message.send_verify_email
        redirect_to waiting_verification_path
    else
        render 'new'
    end
end

routes:

get 'apply', to: 'businesses#new', as: 'apply'
post 'apply', to: 'businesses#apply', as: 'applied'

view:

= simple_form_for @biz, url: apply_path, html: {autocomplete: "off"} do |f|

I understand that the first line of the routes directs a request at /apply to the new action in the controller which creates a new business object and renders the new view, which I have included a snippet from. This snippet includes the form action which directs a successful submission to the apply_path.

My understanding indicates that this apply_path is a named helper for the first routes line when I believe it should be directed to the second line, whose helper would be applied_path, and would then be handled by the apply action on the controller.

What is really causing me confusion is that this functionality works. So the submission is in fact being routed to the second routes line and being handled by the apply action in the controller. If you could explain how this is happening I would appreciate it tremendously. Thank you.

Upvotes: 2

Views: 87

Answers (3)

DMKE
DMKE

Reputation: 4603

The generated form will look like

<form action="/apply" method="post" autocomplete="off" class="simple_form new_business">

Note the method attribute: Because @biz is a new record, SimpleForm knows this should be HTTP POST'ed to the url specified (AFAIK persisted records will still create a method="post" on the form, but an additional hidden field with name="_method" and value="put" is inserted).

Since both route helpers, apply_path and applied_path, just generate the string '/apply', it does not matter which URL you define in your form. This should equally well work:

= simple_form_for @biz, url: applied_path, html: {autocomplete: "off"} do |f|

When you submit the form, your browser creates an HTTP request, like this:

POST /apply HTTP/1.1
<header information>

<post body>

and Journey (the Rails router module) will take the information POST + /apply to find the route to businesses#apply.


To make the route definition a little more concise, you could rewrite it as

scope as: :apply do
  get  '/apply', to: 'businesses#new'
  post '/apply', to: 'businesses#apply'
end

Upvotes: 0

nzifnab
nzifnab

Reputation: 16110

The reason this is working is that you have two named routes that map to the same path. applied_path is /apply, and apply_path is /apply. These two named paths are IDENTICAL. The difference comes when the form performs a POST to /apply, it sees a POST and immediately goes to the second route. While a GET to that same /apply path will go to the first route.

On this note, you only really need to name one of the routes and just use that name everywhere. This is why, when you declare a resource in your routes file:

resources :users

You end up with a "POST /users" and a "GET /users" path which routes to users#create and users#index respectively, based on what kind of request was sent - BUT you only have one users_path named route, which always returns "/users"

Upvotes: 0

Eyeslandic
Eyeslandic

Reputation: 14900

The line

= simple_form_for @bix, url: apply_path

generates something like

<form action="/apply" method="post">
  .. 
</form>

POST is the default method on forms, so when the form is then POST-ed Rails looks at the routes.rb file and sees a match on this line.

post 'apply', to: 'businesses#apply', as: 'applied'

If however you had done it like this

= simple_form_for @bix, url: apply_path, method: :get

The form is submitted via GET and then Rails would find a match on the first line in routes.rb.

get 'apply', to: 'businesses#new', as: 'apply'

It doesn't matter what the name of the routes_helpers are, all that matters is the generated url. I hope that clears thing out, if not, just ask for more clarification.

Upvotes: 1

Related Questions