ruby-on-railsrubyauthenticity-token

Rails authenticity_token cannot be verified when submitting requests to API::V1 module controllers


I've come across a very strange problem with Rails 5. I've two controllers, first as users_controller and second as api/v1/users_controller. Both these controllers have a register action. I am trying to post a form to both these controllers. This form is created as below,

 <%= form_tag('v2/register/user', {id: "add-user-form", class: "jiffle-form", role: "form"}) do%>
   #form body
   <%= submit_tag("Resigter", data: {i18n: "register"}, class:  "btn btn-lg btn-block btn-blue", id: "add-user", type: "submit") %>
<% end %>

Routes,

post "register" => "users#create", :as => "user_registeration_submit"
post "v2/register/user" => "api/v1/users#create"

When I use /register url to submit the form it gets processed successfully. However, when I use v2/register/user url to submit the form I am getting Can't verify CSRF token authenticity error.

Params

Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ADNTIp9alRB/ujRhkoqNuDkzdW6ANfcl/MbPjGLwVd6nwVuG5oi+uVhE9MeZo+1MeyKLbwZYNV31Vy/VH3M2bg==", "sfdc_token"=>"",
 "email"=>"[FILTERED]", "first_name"=>"kjl", "last_name"=>"jk", "contact_no"=>"894892849", "company_name"=>"j", "title"=>"kj",
 "internal_366vagan2"=>"", "consent"=>"true",
 "commit"=>"Register"}

When I use ajax to submit the form to api/v1/users_controller with X-CSRF-TOKEN header in the request it works fine.

Where do I make a change to get my api/v1 controller to work?


Solution

  • You can simply write in application_controller.rb

       protect_from_forgery with: :exception, unless: -> { request.format.json? }
    

    And set default format will be json in routes.rb file

    But better approach:

    In your case, you have to create two namespaces, one for handing API response and second one for FORM handling. Use namespaces in routes.rb file accordingly. And also two different base controller accordingly that inherits from ApplicationController.

    For API

    class Api::V1::ApplicationController < ApplicationController
       protect_from_forgery with: :exception, unless: -> { request.format.json? }
    end
    

    And set default format will be json in routes.rb file

     resources :tasks, defaults: {format: :json}
    

    For FORM View

    Use bydefault settings, or

    class Admin::AdminController < ApplicationController
       protect_from_forgery with: :exception
    end
    #In this case, comment it from main application_controller.rb file:protect_from_forgery with: :exception
    

    Note: here Admin and Api are two namespaces. And routes.rb file will look like:

    #For admin
    namespace :admin do
    
    end 
    
    #For Api
    namespace :api do
        scope module: :v1 do
    
        end
    end 
    

    Hope it will work :)