Nancy Moore
Nancy Moore

Reputation: 2470

How to properely post html form to controller in Ruby on rails 5.2.3

Am new to ruby on rails. Here am trying to post html form to ruby on rails (5.2.3 versions) To this effect, I reference solution found here link

<form accept-charset="UTF-8" method='post' action='http://localhost:3000/user1s'>

      
        <label for='name'>Name</label>
            <input type="text" name='name' placeholder='Enter your name'> <br>
        <label for='password'>password</label>
            <input type="text" name='password' placeholder='Enter your password'> <br>
        <label for='email'>confirm pass</label>
            <input type="text" name='password_confirmation' placeholder='Enter your password_confirmation'> <br>
     
            <input type="submit" value='Save'>
    </form>

user1 controller

class User1sController < ApplicationController
    

  # POST /user1s
  # POST /user1s.json
  def create
    @name = params[:name]
    @password = params[:password]
    @password_confirmation = params[:password_confirmation]
    @user1 = User1.new(name=>@name, password=>@password , password_confirmation=>@password_confirmation)

    respond_to do |format|
      if @user1.save
        format.html { redirect_to @user1, notice: 'User1 was successfully created.' }
        format.json { render :show, status: :created, location: @user1 }
        #format.json {status: :created }
      else
        format.html { render :new }
        format.json { render json: @user1.errors, status: :unprocessable_entity }
      end
    end
  end

  
end

Here is config/routes.rb

Rails.application.routes.draw do
  #resources :user1s
  post '/user1s', to: 'user1s#create', as: 'user1s'  
end

When I run the code am getting the following error

The browser returned a 'null' origin for a request with origin-based forgery protection turned on. This usually means you have the 'no-referrer' Referrer-Policy header enabled, or that the request came from a site that refused to give its origin. This makes it impossible for Rails to verify the source of the requests. Likely the best solution is to change your referrer policy to something less strict like same-origin or strict-same-origin. If you cannot change the referrer policy, you can disable origin checking with the Rails.application.config.action_controller.forgery_protection_origin_check setting.

To mitigate the error above, I referenced link here which suggests solutions below yet cannot get it to work. link 2

at config/application.rb i have

Bundler.require(*Rails.groups)

module Saverecord
  class Application < Rails::Application
    Rails.application.config.action_controller.forgery_protection_origin_check = false
    config.action_controller.allow_forgery_protection = false

    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

  end
end

at application controller I have

class ApplicationController < ActionController::Base   
  # Prevent CSRF attacks by raising an exception.   
  # For APIs, you may want to use :null_session instead.   
  #protect_from_forgery with: :exception   
  protect_from_forgery with: :null_session

  
end  

Upvotes: 4

Views: 4108

Answers (1)

max
max

Reputation: 101891

This is much easier if you just follow the rails conventions.

Start by using strong parameters instead of copying variables twice from the params hash.

class User1sController < ApplicationController
  # POST /user1s
  # POST /user1s.json
  def create
    # Use strong parameters instead  
    @user1 = User1.new(user1_parameters)

    respond_to do |format|
      if @user1.save
        format.html { redirect_to @user1, notice: 'User1 was successfully created.' }
        format.json { render :show, status: :created, location: @user1 }
        #format.json {status: :created }
      else
        format.html { render :new }
        format.json { render json: @user1.errors, status: :unprocessable_entity }
      end
    end
  end

  # ...
  private 
  def user1_parameters
    params.require(:user1).permit(:name, :email, :password, :password_confirmation)
  end
end

Ruby (and Rails) have fantastic features for manipulating hashes. If you are ever copying keys manually from one hash to another you are doing it wrong.

Then use the form helper instead of manually creating a form:

<%= form_with(model: @user1) do |form| %>
  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>
  <div class="field">
    <%= form.label :email %>
    <%= form.email_field :email %>
  </div>
  <div class="field">
    <%= form.label :password %>
    <%= form.password_field :password %>
  </div>
  <div class="field">
    <%= form.label :password_confirmation %>
    <%= form.password_field :password_confirmation %>
  </div>
  <div class="actions">
    <% form.submit %>
  </div>
<% end %>

Rails has built in Cross Site Reference Forgery (CSRF) countermeasures which means that Rails will reject form submission that do not contain a valid CSRF token. When you create a form with form_with (or the older form_tag and form_for) Rails includes a CSRF token as a hidden input in the form.

That means your hand-crafted form is a no go unless you disable the CSRF protection or provide the token which is much more complicated then just using the form helpers.

Your form also does not use the correct name attributes for a nested hash. Rails by convention uses nested hashes:

{
  users1: {
    name: 'foo',
    email: '[email protected]'
    ...
  }
}

The form helper do this by setting the correct name attribute on the inputs:

<input type="email" name='user1[email]' ...>

Which works with params.require(:user1).permit(...). Your form will give an ActionController::ParameterMissing error. You can work around this to use flat hashes but you might as well learn the Rails Way which avoids potential name collisions.

Upvotes: 5

Related Questions