ruby-on-railsvue.jsrails-api

Postman works with Rails 7 API, but POST request from Vue gets 422 error


Vue front end consuming a Rails API. not sure what I am missing. Trying to create a signup form. The users#create route works with a post request via postman with the following raw json request body:

{
    "name": "usertwo",
    "username":"user2",
    "email":"user2@gmail.com",
    "password":"abc123",
    "password_confirmation":"abc123"
}

With the Postman request, the rails logs show the parameters as expected

Started POST "/users" for ::1 at 2023-03-10 17:51:07 -0500
Processing by UsersController#create as */*
  Parameters: {"name"=>"usertwo", "username"=>"user2", "email"=>"user2@gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "user"=>{"name"=>"usertwo", "username"=>"user2", "email"=>"user2@gmail.com"}}
{"rack.version"=>[1, 6], "rack.errors"=>#<IO:<STDERR>>, "rack.multithread"=>true, "rack.multiprocess"=>false, "rack.run_once"=>false, "rack.url_scheme"=>"http", "SCRIPT_NAME"=>"", "QUERY_STRING"=>"", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_SOFTWARE"=>"puma 5.6.5 Birdie's Version", "GATEWAY_INTERFACE"=>"CGI/1.2", "REQUEST_METHOD"=>"POST", "REQUEST_PATH"=>"/users", "REQUEST_URI"=>"/users", "HTTP_VERSION"=>"HTTP/1.1", "CONTENT_TYPE"=>"application/json", "HTTP_USER_AGENT"=>"PostmanRuntime/7.31.1", "HTTP_ACCEPT"=>"*/*", "HTTP_POSTMAN_TOKEN"=>"d2b6847e-ff06-4dde-a53c-b010bd6c7e44", "HTTP_HOST"=>"localhost:3000", "HTTP_ACCEPT_ENCODING"=>"gzip, deflate, br", "HTTP_CONNECTION"=>"keep-alive", "CONTENT_LENGTH"=>"143", "puma.request_body_wait"=>1, "SERVER_NAME"=>"localhost", "SERVER_PORT"=>"3000", "PATH_INFO"=>"/users", "REMOTE_ADDR"=>"::1", "puma.socket"=>#<TCPSocket:fd 23, AF_INET6, ::1, 3000>, "rack.hijack?"=>true, "rack.hijack"=>#<Puma::Client:0x23adc @ready=true>, "rack.input"=>#<StringIO:0x00007f85709b4590>, "rack.after_reply"=>[], "puma.config"=>#<Puma::Configuration:0x00007f856f8eee40 @options=#<Puma::UserFileDefaultOptions:0x00007f856f8eebc0 @user_options={:app=>#<FanistatRails::Application>, :environment=>"development"}, @file_options={:default_host=>"localhost", :min_threads=>5, :max_threads=>5, :worker_timeout=>3600, :binds=>["tcp://localhost:3000"], :environment=>"development", :pidfile=>"tmp/pids/server.pid"}, @default_options={:min_threads=>0, :max_threads=>5, :log_requests=>false, :debug=>false, :binds=>["tcp://localhost:3000"], :workers=>0, :silence_single_worker_warning=>false, :mode=>:http, :worker_check_interval=>5, :worker_timeout=>60, :worker_boot_timeout=>60, :worker_shutdown_timeout=>30, :worker_culling_strategy=>:youngest, :remote_address=>:socket, :tag=>"fanistat-rails", :environment=>"development", :rackup=>"config.ru", :logger=>#<IO:<STDOUT>>, :persistent_timeout=>20, :first_data_timeout=>30, :raise_exception_on_sigterm=>true, :max_fast_inline=>10, :io_selector_backend=>:auto, :mutate_stdout_and_stderr_to_sync_on_write=>true, :Verbose=>false, :Silent=>false, :server=>nil, :log_stdout=>true, :Port=>3000, :Host=>"localhost", :DoNotReverseLookup=>true, :config=>"config.ru", :daemonize=>false, :pid=>"/Users/darius/IdeaProjects/fanistat-rails/tmp/pids/server.pid", :caching=>nil, :restart_cmd=>"bin/rails server  --restart", :early_hints=>nil, :preload_app=>false}>, @plugins=#<Puma::PluginLoader:0x00007f856f8eeb48 @instances=[#<#<Class:0x00007f85734afab0>:0x00007f85734af920>]>, @user_dsl=#<Puma::DSL:0x00007f856f8eeaa8 @config=#<Puma::Configuration:0x00007f856f8eee40 ...>, @options={:app=>#<FanistatRails::Application>, :environment=>"development"}, @plugins=[]>, @file_dsl=#<Puma::DSL:0x00007f856f8eea30 @config=#<Puma::Configuration:0x00007f856f8eee40 ...>, @options={:default_host=>"localhost", :min_threads=>5, :max_threads=>5, :worker_timeout=>3600, :binds=>["tcp://localhost:3000"], :environment=>"development", :pidfile=>"tmp/pids/server.pid"}, @plugins=[], @path="config/puma.rb">, @default_dsl=#<Puma::DSL:0x00007f856f8ee9b8 @config=#<Puma::Configuration:0x00007f856f8eee40 ...>, @options={:min_threads=>0, :max_threads=>5, :log_requests=>false, :debug=>false, :binds=>["tcp://localhost:3000"], :workers=>0, :silence_single_worker_warning=>false, :mode=>:http, :worker_check_interval=>5, :worker_timeout=>60, :worker_boot_timeout=>60, :worker_shutdown_timeout=>30, :worker_culling_strategy=>:youngest, :remote_address=>:socket, :tag=>"fanistat-rails", :environment=>"development", :rackup=>"config.ru", :logger=>#<IO:<STDOUT>>, :persistent_timeout=>20, :first_data_timeout=>30, :raise_exception_on_sigterm=>true, :max_fast_inline=>10, :io_selector_backend=>:auto, :mutate_stdout_and_stderr_to_sync_on_write=>true, :Verbose=>false, :Silent=>false, :server=>nil, :log_stdout=>true, :Port=>3000, :Host=>"localhost", :DoNotReverseLookup=>true, :config=>"config.ru", :daemonize=>false, :pid=>"/Users/darius/IdeaProjects/fanistat-rails/tmp/pids/server.pid", :caching=>nil, :restart_cmd=>"bin/rails server  --restart", :early_hints=>nil, :preload_app=>false}, @plugins=[]>>, "action_dispatch.parameter_filter"=>[:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn], "action_dispatch.redirect_filter"=>[], "action_dispatch.secret_key_base"=>"68e0398fd4ffecfd2d234b628b457bf0d16cebb043f611613e24d38a6d77172904ae723d12bd877dabe9e73a573c405f613b4902e787b4e094ec03ac7ae04026", "action_dispatch.show_exceptions"=>true, "action_dispatch.show_detailed_exceptions"=>true, "action_dispatch.log_rescued_responses"=>true, "action_dispatch.logger"=>#<ActiveSupport::Logger:0x00007f856ce9dd08 @level=0, @progname=nil, @default_formatter=#<Logger::Formatter:0x00007f856cedf898 @datetime_format=nil>, @formatter=#<ActiveSupport::Logger::SimpleFormatter:0x00007f856ce9d998 @datetime_format=nil, @thread_key="activesupport_tagged_logging_tags:10560">, @logdev=#<Logger::LogDevice:0x00007f856cedcdf0 @shift_period_suffix="%Y%m%d", @shift_size=1048576, @shift_age=0, @filename="/Users/darius/IdeaProjects/fanistat-rails/log/development.log", @dev=#<File:/Users/darius/IdeaProjects/fanistat-rails/log/development.log>, @binmode=false, @mon_data=#<Monitor:0x00007f856cedc058>, @mon_data_owner_object_id=3300>>, "action_dispatch.backtrace_cleaner"=>#<Rails::BacktraceCleaner:0x00007f8573517480 @silencers=[#<Proc:0x00007f8573517048 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-7.0.4.2/lib/active_support/backtrace_cleaner.rb:100>, #<Proc:0x00007f8573516fd0 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-7.0.4.2/lib/active_support/backtrace_cleaner.rb:104>, #<Proc:0x00007f8573516ee0 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/railties-7.0.4.2/lib/rails/backtrace_cleaner.rb:24>], @filters=[#<Proc:0x00007f85735170e8 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-7.0.4.2/lib/active_support/backtrace_cleaner.rb:96>, #<Proc:0x00007f8573516f30 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/railties-7.0.4.2/lib/rails/backtrace_cleaner.rb:14>, #<Proc:0x00007f8573516f08 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/railties-7.0.4.2/lib/rails/backtrace_cleaner.rb:17>], @root="/Users/darius/IdeaProjects/fanistat-rails/">, "action_dispatch.key_generator"=>#<ActiveSupport::CachingKeyGenerator:0x00007f85731275a0 @key_generator=#<ActiveSupport::KeyGenerator:0x00007f8573127640 @secret="68e0398fd4ffecfd2d234b628b457bf0d16cebb043f611613e24d38a6d77172904ae723d12bd877dabe9e73a573c405f613b4902e787b4e094ec03ac7ae04026", @iterations=1000, @hash_digest_class=OpenSSL::Digest::SHA256>, @cache_keys=#<Concurrent::Map:0x00007f8573127578 entries=2 default_proc=nil>>, "action_dispatch.http_auth_salt"=>"http authentication", "action_dispatch.signed_cookie_salt"=>"signed cookie", "action_dispatch.encrypted_cookie_salt"=>"encrypted cookie", "action_dispatch.encrypted_signed_cookie_salt"=>"signed encrypted cookie", "action_dispatch.authenticated_encrypted_cookie_salt"=>"authenticated encrypted cookie", "action_dispatch.use_authenticated_cookie_encryption"=>true, "action_dispatch.encrypted_cookie_cipher"=>nil, "action_dispatch.signed_cookie_digest"=>nil, "action_dispatch.cookies_serializer"=>:json, "action_dispatch.cookies_digest"=>nil, "action_dispatch.cookies_rotations"=>#<ActiveSupport::Messages::RotationConfiguration:0x00007f856cbd4fe0 @signed=[], @encrypted=[]>, "action_dispatch.cookies_same_site_protection"=>#<Proc:0x00007f85735166c0 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/railties-7.0.4.2/lib/rails/application.rb:614>, "action_dispatch.use_cookies_with_metadata"=>true, "action_dispatch.content_security_policy"=>nil, "action_dispatch.content_security_policy_report_only"=>false, "action_dispatch.content_security_policy_nonce_generator"=>nil, "action_dispatch.content_security_policy_nonce_directives"=>nil, "action_dispatch.permissions_policy"=>nil, "action_dispatch.routes"=>#<ActionDispatch::Routing::RouteSet:0x00007f85724d81c8>, "ROUTES_8080_SCRIPT_NAME"=>"", "ORIGINAL_FULLPATH"=>"/users", "ORIGINAL_SCRIPT_NAME"=>"", "rack.cors"=>#<Rack::Cors::Result:0x00007f856fb6fd68 @preflight=false, @hit=false, @miss_reason="no-origin">, "action_dispatch.authorized_host"=>"localhost", "action_dispatch.request_id"=>"184f1c0d-9aff-4038-b245-9ac477fc9383", "action_dispatch.remote_ip"=>#<ActionDispatch::RemoteIp::GetIp:0x00007f856fb4f7c0 @req=#<ActionDispatch::Request POST "http://localhost:3000/users" for ::1>, @check_ip=true, @proxies=[#<IPAddr: IPv4:127.0.0.0/255.0.0.0>, #<IPAddr: IPv6:0000:0000:0000:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>, #<IPAddr: IPv6:fc00:0000:0000:0000:0000:0000:0000:0000/fe00:0000:0000:0000:0000:0000:0000:0000>, #<IPAddr: IPv4:10.0.0.0/255.0.0.0>, #<IPAddr: IPv4:172.16.0.0/255.240.0.0>, #<IPAddr: IPv4:192.168.0.0/255.255.0.0>], @ip="::1">, "action_dispatch.request.path_parameters"=>{:controller=>"users", :action=>"create"}, "action_controller.instance"=>#<UsersController:0x000000000475e0>, "action_dispatch.request.content_type"=>#<Mime::Type:0x00007f857083d4a0 @synonyms=["text/x-json", "application/jsonrequest"], @symbol=:json, @string="application/json", @hash=2390181677827773329>, "RAW_POST_DATA"=>"{\n    \"name\": \"usertwo\",\n    \"username\":\"user2\",\n    \"email\":\"user2@gmail.com\",\n    \"password\":\"abc123\",\n    \"password_confirmation\":\"abc123\"\n}", "action_dispatch.request.request_parameters"=>{"name"=>"usertwo", "username"=>"user2", "email"=>"user2@gmail.com", "password"=>"abc123", "password_confirmation"=>"abc123", "user"=>{"name"=>"usertwo", "username"=>"user2", "email"=>"user2@gmail.com"}}, "rack.request.query_string"=>"", "rack.request.query_hash"=>{}, "action_dispatch.request.query_parameters"=>{}, "action_dispatch.request.parameters"=>{"name"=>"usertwo", "username"=>"user2", "email"=>"user2@gmail.com", "password"=>"abc123", "password_confirmation"=>"abc123", "controller"=>"users", "action"=>"create", "user"=>{"name"=>"usertwo", "username"=>"user2", "email"=>"user2@gmail.com"}}, "action_dispatch.request.accepts"=>[#<Mime::Type:0x00007f85748cf130 @synonyms=[], @symbol=nil, @string="*/*", @hash=-2437670371779655827>], "action_dispatch.request.formats"=>[#<Mime::Type:0x00007f85748cf130 @synonyms=[], @symbol=nil, @string="*/*", @hash=-2437670371779655827>]}
Unpermitted parameter: :user. Context: { controller: UsersController, action: create, request: #<ActionDispatch::Request:0x00007f85748d8e10>, params: {"name"=>"usertwo", "username"=>"user2", "email"=>"user2@gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "controller"=>"users", "action"=>"create", "user"=>{"name"=>"usertwo", "username"=>"user2", "email"=>"user2@gmail.com"}} }
  TRANSACTION (0.3ms)  BEGIN
  ↳ app/controllers/users_controller.rb:20:in `create'
  User Exists? (4.8ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2  [["email", "user2@gmail.com"], ["LIMIT", 1]]
  ↳ app/controllers/users_controller.rb:20:in `create'

here is my register action from Vuex:

  register ({ commit }, user) {
    return new Promise((resolve, reject) => {
      commit('auth_request')
      console.log('in store register action, root_api: ', process.env.VUE_APP_ROOT_API)
      API({ url: '/users', data: user, method: 'POST' })
        .then(async resp => {
          const token = 'Token ' + resp.data.user.token
          const user = resp.data.user
          localStorage.setItem('token', token)
          API.defaults.headers.common.token = token
          commit('auth_success')
          commit('set_user', user)
          resolve(resp)
        })
        .catch(err => {
          commit('auth_error', err)
          localStorage.removeItem('token')
          reject(err)
        })
    })
  },

the signup form component:

<template>
  <card-component
    title="SignUp"
    icon="lock"
  >
    <router-link
      slot="button"
      to="/"
      class="button is-small"
    >
      Dashboard
    </router-link>

    <form
      method="POST"
      @submit.prevent="submit"
    >
      <b-field label="Name">
        <b-input
          v-model="form.name"
          name="name"
          type="string"
          required
        />
      </b-field>
      <b-field label="Username">
        <b-input
          v-model="form.username"
          name="username"
          type="string"
          required
        />
      </b-field>
      <b-field label="Email">
        <b-input
          v-model="form.email"
          name="email"
          type="email"
          required
        />
      </b-field>

      <b-field label="Password">
        <b-input
          v-model="form.password"
          type="password"
          name="password"
          required
        />
      </b-field>

      <b-field label="Password Confirmation">
        <b-input
          v-model="form.password_confirmation"
          type="password"
          name="password_confirmation"
          required
        />
      </b-field>

      <hr>

      <b-field grouped>
        <div class="control">
          <b-button
            native-type="submit"
            type="is-black"
            :loading="isLoading"
          >
            Signup
          </b-button>
        </div>
        <div class="control">
          <router-link
            to="/"
            class="button is-outlined is-black"
          >
            Dashboard
          </router-link>
        </div>
      </b-field>
    </form>
  </card-component>
</template>

<script>
import { defineComponent } from 'vue'
import CardComponent from '@/components/CardComponent.vue'

export default defineComponent({
  name: 'SignUpView',
  components: { CardComponent },
  data () {
    return {
      isLoading: false,
      form: {
        username: 'prettyricky14',
        password: 'my-secret'
      }
    }
  },
  methods: {
    submit () {
      this.isLoading = true
      this.$store.dispatch('register', this.form)
      this.isLoading = false
      this.$router.push('/')
    }
  }
})

The network tab shows the payload from the request from the front end as:

{username: "prettyricky14", password: "abc123", name: "pr", email: "pr@gmail.com",…}

email: "pr@gmail.com"
name: "pr"
password: "abc123"
password_confirmation: "abc123"
username: "prettyricky14"

The Rails logs show no parameters being delivered and ends with a 422 response:

Started POST "/users" for ::1 at 2023-03-10 18:27:16 -0500
Processing by UsersController#create as */*
{"rack.version"=>[1, 6], "rack.errors"=>#<IO:<STDERR>>, "rack.multithread"=>true, "rack.multiprocess"=>false, "rack.run_once"=>false, "rack.url_scheme"=>"http", "SCRIPT_NAME"=>"", "QUERY_STRING"=>"", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_SOFTWARE"=>"puma 5.6.5 Birdie's Version", "GATEWAY_INTERFACE"=>"CGI/1.2", "REQUEST_METHOD"=>"POST", "REQUEST_PATH"=>"/users", "REQUEST_URI"=>"/users", "HTTP_VERSION"=>"HTTP/1.1", "HTTP_HOST"=>"localhost:3000", "HTTP_CONNECTION"=>"keep-alive", "CONTENT_LENGTH"=>"116", "HTTP_SEC_CH_UA"=>"\"Chromium\";v=\"110\", \"Not A(Brand\";v=\"24\", \"Brave\";v=\"110\"", "HTTP_ACCEPT"=>"application/vnd.api+json", "CONTENT_TYPE"=>"application/vnd.api+json", "HTTP_SEC_CH_UA_MOBILE"=>"?0", "HTTP_AUTHORIZATION"=>"JWT null", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36", "HTTP_SEC_CH_UA_PLATFORM"=>"\"macOS\"", "HTTP_SEC_GPC"=>"1", "HTTP_ACCEPT_LANGUAGE"=>"en-US,en", "HTTP_ORIGIN"=>"http://localhost:8080", "HTTP_SEC_FETCH_SITE"=>"same-site", "HTTP_SEC_FETCH_MODE"=>"cors", "HTTP_SEC_FETCH_DEST"=>"empty", "HTTP_REFERER"=>"http://localhost:8080/", "HTTP_ACCEPT_ENCODING"=>"gzip, deflate, br", "puma.request_body_wait"=>1, "SERVER_NAME"=>"localhost", "SERVER_PORT"=>"3000", "PATH_INFO"=>"/users", "REMOTE_ADDR"=>"::1", "puma.socket"=>#<TCPSocket:fd 18, AF_INET6, ::1, 3000>, "rack.hijack?"=>true, "rack.hijack"=>#<Puma::Client:0x23c08 @ready=true>, "rack.input"=>#<StringIO:0x00007f8574565f30>, "rack.after_reply"=>[], "puma.config"=>#<Puma::Configuration:0x00007f856f8eee40 @options=#<Puma::UserFileDefaultOptions:0x00007f856f8eebc0 @user_options={:app=>#<FanistatRails::Application>, :environment=>"development"}, @file_options={:default_host=>"localhost", :min_threads=>5, :max_threads=>5, :worker_timeout=>3600, :binds=>["tcp://localhost:3000"], :environment=>"development", :pidfile=>"tmp/pids/server.pid"}, @default_options={:min_threads=>0, :max_threads=>5, :log_requests=>false, :debug=>false, :binds=>["tcp://localhost:3000"], :workers=>0, :silence_single_worker_warning=>false, :mode=>:http, :worker_check_interval=>5, :worker_timeout=>60, :worker_boot_timeout=>60, :worker_shutdown_timeout=>30, :worker_culling_strategy=>:youngest, :remote_address=>:socket, :tag=>"fanistat-rails", :environment=>"development", :rackup=>"config.ru", :logger=>#<IO:<STDOUT>>, :persistent_timeout=>20, :first_data_timeout=>30, :raise_exception_on_sigterm=>true, :max_fast_inline=>10, :io_selector_backend=>:auto, :mutate_stdout_and_stderr_to_sync_on_write=>true, :Verbose=>false, :Silent=>false, :server=>nil, :log_stdout=>true, :Port=>3000, :Host=>"localhost", :DoNotReverseLookup=>true, :config=>"config.ru", :daemonize=>false, :pid=>"/Users/darius/IdeaProjects/fanistat-rails/tmp/pids/server.pid", :caching=>nil, :restart_cmd=>"bin/rails server  --restart", :early_hints=>nil, :preload_app=>false}>, @plugins=#<Puma::PluginLoader:0x00007f856f8eeb48 @instances=[#<#<Class:0x00007f85734afab0>:0x00007f85734af920>]>, @user_dsl=#<Puma::DSL:0x00007f856f8eeaa8 @config=#<Puma::Configuration:0x00007f856f8eee40 ...>, @options={:app=>#<FanistatRails::Application>, :environment=>"development"}, @plugins=[]>, @file_dsl=#<Puma::DSL:0x00007f856f8eea30 @config=#<Puma::Configuration:0x00007f856f8eee40 ...>, @options={:default_host=>"localhost", :min_threads=>5, :max_threads=>5, :worker_timeout=>3600, :binds=>["tcp://localhost:3000"], :environment=>"development", :pidfile=>"tmp/pids/server.pid"}, @plugins=[], @path="config/puma.rb">, @default_dsl=#<Puma::DSL:0x00007f856f8ee9b8 @config=#<Puma::Configuration:0x00007f856f8eee40 ...>, @options={:min_threads=>0, :max_threads=>5, :log_requests=>false, :debug=>false, :binds=>["tcp://localhost:3000"], :workers=>0, :silence_single_worker_warning=>false, :mode=>:http, :worker_check_interval=>5, :worker_timeout=>60, :worker_boot_timeout=>60, :worker_shutdown_timeout=>30, :worker_culling_strategy=>:youngest, :remote_address=>:socket, :tag=>"fanistat-rails", :environment=>"development", :rackup=>"config.ru", :logger=>#<IO:<STDOUT>>, :persistent_timeout=>20, :first_data_timeout=>30, :raise_exception_on_sigterm=>true, :max_fast_inline=>10, :io_selector_backend=>:auto, :mutate_stdout_and_stderr_to_sync_on_write=>true, :Verbose=>false, :Silent=>false, :server=>nil, :log_stdout=>true, :Port=>3000, :Host=>"localhost", :DoNotReverseLookup=>true, :config=>"config.ru", :daemonize=>false, :pid=>"/Users/darius/IdeaProjects/fanistat-rails/tmp/pids/server.pid", :caching=>nil, :restart_cmd=>"bin/rails server  --restart", :early_hints=>nil, :preload_app=>false}, @plugins=[]>>, "action_dispatch.parameter_filter"=>[:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn], "action_dispatch.redirect_filter"=>[], "action_dispatch.secret_key_base"=>"68e0398fd4ffecfd2d234b628b457bf0d16cebb043f611613e24d38a6d77172904ae723d12bd877dabe9e73a573c405f613b4902e787b4e094ec03ac7ae04026", "action_dispatch.show_exceptions"=>true, "action_dispatch.show_detailed_exceptions"=>true, "action_dispatch.log_rescued_responses"=>true, "action_dispatch.logger"=>#<ActiveSupport::Logger:0x00007f856ce9dd08 @level=0, @progname=nil, @default_formatter=#<Logger::Formatter:0x00007f856cedf898 @datetime_format=nil>, @formatter=#<ActiveSupport::Logger::SimpleFormatter:0x00007f856ce9d998 @datetime_format=nil, @thread_key="activesupport_tagged_logging_tags:10560">, @logdev=#<Logger::LogDevice:0x00007f856cedcdf0 @shift_period_suffix="%Y%m%d", @shift_size=1048576, @shift_age=0, @filename="/Users/darius/IdeaProjects/fanistat-rails/log/development.log", @dev=#<File:/Users/darius/IdeaProjects/fanistat-rails/log/development.log>, @binmode=false, @mon_data=#<Monitor:0x00007f856cedc058>, @mon_data_owner_object_id=3300>>, "action_dispatch.backtrace_cleaner"=>#<Rails::BacktraceCleaner:0x00007f8573517480 @silencers=[#<Proc:0x00007f8573517048 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-7.0.4.2/lib/active_support/backtrace_cleaner.rb:100>, #<Proc:0x00007f8573516fd0 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-7.0.4.2/lib/active_support/backtrace_cleaner.rb:104>, #<Proc:0x00007f8573516ee0 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/railties-7.0.4.2/lib/rails/backtrace_cleaner.rb:24>], @filters=[#<Proc:0x00007f85735170e8 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/activesupport-7.0.4.2/lib/active_support/backtrace_cleaner.rb:96>, #<Proc:0x00007f8573516f30 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/railties-7.0.4.2/lib/rails/backtrace_cleaner.rb:14>, #<Proc:0x00007f8573516f08 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/railties-7.0.4.2/lib/rails/backtrace_cleaner.rb:17>], @root="/Users/darius/IdeaProjects/fanistat-rails/">, "action_dispatch.key_generator"=>#<ActiveSupport::CachingKeyGenerator:0x00007f85731275a0 @key_generator=#<ActiveSupport::KeyGenerator:0x00007f8573127640 @secret="68e0398fd4ffecfd2d234b628b457bf0d16cebb043f611613e24d38a6d77172904ae723d12bd877dabe9e73a573c405f613b4902e787b4e094ec03ac7ae04026", @iterations=1000, @hash_digest_class=OpenSSL::Digest::SHA256>, @cache_keys=#<Concurrent::Map:0x00007f8573127578 entries=2 default_proc=nil>>, "action_dispatch.http_auth_salt"=>"http authentication", "action_dispatch.signed_cookie_salt"=>"signed cookie", "action_dispatch.encrypted_cookie_salt"=>"encrypted cookie", "action_dispatch.encrypted_signed_cookie_salt"=>"signed encrypted cookie", "action_dispatch.authenticated_encrypted_cookie_salt"=>"authenticated encrypted cookie", "action_dispatch.use_authenticated_cookie_encryption"=>true, "action_dispatch.encrypted_cookie_cipher"=>nil, "action_dispatch.signed_cookie_digest"=>nil, "action_dispatch.cookies_serializer"=>:json, "action_dispatch.cookies_digest"=>nil, "action_dispatch.cookies_rotations"=>#<ActiveSupport::Messages::RotationConfiguration:0x00007f856cbd4fe0 @signed=[], @encrypted=[]>, "action_dispatch.cookies_same_site_protection"=>#<Proc:0x00007f85735166c0 /Users/darius/.rvm/rubies/ruby-3.0.0/lib/ruby/gems/3.0.0/gems/railties-7.0.4.2/lib/rails/application.rb:614>, "action_dispatch.use_cookies_with_metadata"=>true, "action_dispatch.content_security_policy"=>nil, "action_dispatch.content_security_policy_report_only"=>false, "action_dispatch.content_security_policy_nonce_generator"=>nil, "action_dispatch.content_security_policy_nonce_directives"=>nil, "action_dispatch.permissions_policy"=>nil, "action_dispatch.routes"=>#<ActionDispatch::Routing::RouteSet:0x00007f85724d81c8>, "ROUTES_8080_SCRIPT_NAME"=>"", "ORIGINAL_FULLPATH"=>"/users", "ORIGINAL_SCRIPT_NAME"=>"", "rack.cors"=>#<Rack::Cors::Result:0x00007f8574565a08 @preflight=false, @hit=true>, "action_dispatch.authorized_host"=>"localhost", "action_dispatch.request_id"=>"e24d0ddc-62b0-42ce-ada1-d2ab408db595", "action_dispatch.remote_ip"=>#<ActionDispatch::RemoteIp::GetIp:0x00007f8574563cf8 @req=#<ActionDispatch::Request POST "http://localhost:3000/users" for ::1>, @check_ip=true, @proxies=[#<IPAddr: IPv4:127.0.0.0/255.0.0.0>, #<IPAddr: IPv6:0000:0000:0000:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>, #<IPAddr: IPv6:fc00:0000:0000:0000:0000:0000:0000:0000/fe00:0000:0000:0000:0000:0000:0000:0000>, #<IPAddr: IPv4:10.0.0.0/255.0.0.0>, #<IPAddr: IPv4:172.16.0.0/255.240.0.0>, #<IPAddr: IPv4:192.168.0.0/255.255.0.0>], @ip="::1">, "action_dispatch.request.path_parameters"=>{:controller=>"users", :action=>"create"}, "action_controller.instance"=>#<UsersController:0x00000000047838>, "action_dispatch.request.content_type"=>#<Mime::Type:0x00007f8570a52740 @synonyms=[], @symbol=nil, @string="application/vnd.api+json", @hash=1824596358230126664>, "action_dispatch.request.request_parameters"=>{}, "rack.request.query_string"=>"", "rack.request.query_hash"=>{}, "action_dispatch.request.query_parameters"=>{}, "action_dispatch.request.parameters"=>{"controller"=>"users", "action"=>"create"}, "action_dispatch.request.accepts"=>[#<Mime::Type:0x00007f8570a51778 @synonyms=[], @symbol=nil, @string="application/vnd.api+json", @hash=1824596358230126664>], "action_dispatch.request.formats"=>[]}
  TRANSACTION (1.9ms)  BEGIN
  ↳ app/controllers/users_controller.rb:20:in `create'
  User Exists? (19.2ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" IS NULL LIMIT $1  [["LIMIT", 1]]
  ↳ app/controllers/users_controller.rb:20:in `create'
  User Exists? (0.3ms)  SELECT 1 AS one FROM "users" WHERE "users"."username" IS NULL LIMIT $1  [["LIMIT", 1]]
  ↳ app/controllers/users_controller.rb:20:in `create'
  TRANSACTION (2.5ms)  ROLLBACK
  ↳ app/controllers/users_controller.rb:20:in `create'
Completed 422 Unprocessable Entity in 466ms (Views: 1.0ms | ActiveRecord: 39.5ms | Allocations: 8531)

Adding my api request config file which might be having an effect:

import axios from 'axios'

export default axios.create({
  baseURL: process.env.VUE_APP_ROOT_API,
  headers: {
    // 'Content-Type': 'application/json',
    'Content-Type': 'application/vnd.api+json',
    Accept: 'application/vnd.api+json',
    Authorization: 'JWT ' + localStorage.getItem('token')
  },
  xsrfCookieName: 'csrftoken',
  xsrfHeaderName: 'X-CSRFToken',
  withCredentials: false
})

Solution

  • Figured this out I think.

    Changing Content-type header from 'Content-Type': 'application/vnd.api+json' to 'Content-Type': 'application/json' (matching Postman headers) seems to work.