Having trouble with a 400 Bad Request error when sending a POST request from my Vue application to my Rails API

Currently delving into the world of Rails and Vue, I decided to take on a small project involving a basic Rails API and Vue app to practice making GET and POST requests from my Vue app to the Rails API. While GET requests are working smoothly, I'm encountering a 400 Bad Request error due to incorrect syntax when attempting to send POST requests. Interestingly, when testing with Insomnia (similar to Postman), the POST requests are successful. However, utilizing my Vue app for POST requests leads to a 400 error.

This is how my Rails controller is set up:

def create
    @todo = Todo.new(todo_params)
    if @todo.save
        render :show, status: :created, location: @todo
    else
        render json: @todo.errors, status: :unprocessable_entity
    end
end

...

private

    def set_todo
        @todo = Todo.find(params[:id])
    end

    def todo_params
        params.require(:todo).permit(:title, :description, :finished)
    end

In my Vue app, I have a simple text input field intended for submitting data to my Rails backend:

<template>
<input type="text" v-model="postBody"/>
<button v-on:click="submit()">Submit</button> 
</template>

<script>
import axios from 'axios';
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      todos: [],
      errors: [],
      postBody: ''
    }
  },
methods: {
    submit() {axios.post(`http://localhost:3000/todos/`, { 
        headers: {
          'Content-Type': 'application/json; charset=UTF-8',
        },
        body: JSON.stringify(this.postBody) 
      })
      .then(response => response.data)
      .catch(e => {
        this.errors.push(e)
      })
    }
  }
}
</script>

I attempt to make a POST request in JSON format through the text input to the endpoint http://localhost:3000/todos/:

{
  "title": "Sweets",
  "description": "Buy cookies",
  "finished": false
}

Upon submission, the browser displays the following error message:

{status: 400, error: "Bad Request",…}
error: "Bad Request"
exception: "#<ActionController::ParameterMissing: param is missing or the value is empty: todo>"
status: 400
traces: {Application Trace: [{id: 1, trace: "app/controllers/todos_controller.rb:51:in `todo_params'"},…],…}
Application Trace: [{id: 1, trace: "app/controllers/todos_controller.rb:51:in `todo_params'"},…]
0: {id: 1, trace: "app/controllers/todos_controller.rb:51:in `todo_params'"}
1: {id: 2, trace: "app/controllers/todos_controller.rb:24:in `create'"}

The terminal output from my local Rails server while testing this locally in both Vue and Rails reads:

Started POST "/todos/" for ::1 at 2020-09-21 12:09:16 +0800
Processing by TodosController#create as JSON
  Parameters: {"headers"=>{"Content-Type"=>"application/json; charset=UTF-8"}, "body"=>"\"{   \\\"title\\\": \\\"Sweets\\\", \\t\\\"description\\\": \\\"Buy cookies\\\",   \\\"finished\\\": false }\"", "todo"=>{}}
Completed 400 Bad Request in 0ms (ActiveRecord: 0.0ms)
  
ActionController::ParameterMissing (param is missing or the value is empty: todo):
  
app/controllers/todos_controller.rb:51:in `todo_params'
app/controllers/todos_controller.rb:24:in `create'

It seems that the issue lies within strong parameters in my Rails controller. Removing the required params with .require(:todo) allows the POST to go through, but all JSON fields end up null:

  {
    "id": 6,
    "title": null,
    "description": null,
    "finished": null
  }

Further attempts to investigate whether the problem stemmed from how form data was sent from my Vue app to the Rails endpoint, including using JSON.stringify on the body, did not yield any positive results.

After three days of trying to tackle this issue without success, I am reaching out for assistance. Any guidance would be greatly appreciated! :)

Answer №1

To start off, make sure to include the title, description, and other details under the todo key in the JSON payload when submitting data in Rails.

Also, remember that the headers should be passed in as part of the configuration object for the axios request, not within the payload argument. The first argument for post should contain the data, while the configuration goes in as the second argument.

Lastly, there's no need to manually convert your data to a JSON string before sending it with axios. Axios will handle this conversion automatically for you.

Consider using the following axios request format:

axios.post(
  `http://localhost:3000/todos/`,
  { todo: this.postBody },
  { headers: { 'Content-Type': 'application/json; charset=UTF-8' }
)

Answer №2

Delving into the world of error messages in Rails console led me to a breakthrough realization - the issue was not with the Rails API or strong params, but rather with how I structured the inputs to avoid sending malformed JSON to my Rails endpoint. Consulting the npm axios documentation proved to be incredibly helpful.

Instead of relying on a single text input field in my Vue app, I opted to create a form with fields that corresponded directly to my parameters:

<form @submit.prevent="onSubmit">
  <div class="input">
    <label for="title">Title</label>
    <input
       type="text"
       id="title"
       v-model="title">
  </div>
  <div class="input">
    <label for="name">Description</label>
    <input
      type="text"
      id="description"
      v-model="description">
  </div>
  <div class="input">
    <label for="finished">Finished?</label>
    <input
      type="text"
      id="finished"
      v-model="finished">
  </div>
  <div class="submit">
    <button type="submit">Submit</button>
  </div>
</form>

This setup, paired with the following methods:

methods: {
    onSubmit() {
      const formData = {
      title: this.title,
      description: this.description,
      finished: this.finished      
      }
      axios({
        method: "POST",
        url: "http://localhost:3000/todos/",
        headers: {"Content-Type": "application/json"},
        data: formData
      })
      .then(response => { 
        console.log(response);
      })
      .catch(e => {
      this.errors.push(e)
      })
    },

proved to be the solution I needed! My ability to POST to the Rails API was restored. While I may not fully grasp why it worked, I am open to any insights for my personal growth and understanding. After all, every learning opportunity is valuable, even if it's not directly tied to the initial problem at hand.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why does the for loop function correctly with console.log but not with innerHTML?

Hello! I'm completely new to JavaScript, so please excuse any oversight... Below is the code that runs when a button on the page is clicked: function getNumbers() { var firstValue = document.getElementById("time_one").value; var ...

Checking File Upload Progress in HTML and PHP

As a newcomer, I've been struggling to find a solution to an issue I'm facing. My concern is regarding a form that is meant to upload a file and send it via email. How can I display the progress status of the file being uploaded? It seems that us ...

Accessing the Nuxt store in module mode from a JavaScript file

I'm facing a challenge with my Nuxt app, where I have an AuthService within a namespaced store. The issue lies in how to import the store into my AuthService so that I can commit mutations from there. In some examples I've seen, the store is imp ...

Trigger a Redux action with the following action as the payload in order to display a Material UI snackbar or dialog

Currently, my project involves using React along with Redux and Material UI to develop a web application. The web app consists of numerous pages and components. It is common practice to have a snackbar or dialog interact directly with the user's actio ...

Share the Nav tag value or name during an OnClick event within ReactJS

I've been facing a minor issue that I just can't seem to figure out - how do I pass a value to my OnClick event? It's crucial for me to pass this value as it corresponds to the options in my menu and is essential for some processes: This is ...

Retrieving results from a Node.js application that utilizes multithreading

A new function called diversify() has been developed to execute an expensive function f() in parallel on all the cores of the machine in which it is being deployed. Additionally, a mechanism has been implemented so that when f() returns a value on one core ...

After a duration of 4 minutes, an ERR_EMPTY_RESPONSE is thrown in response to the

My angular 5 node app involves sending a request to the server and waiting for a response. There are instances where the response takes around 5-6 minutes to arrive. However, an ERR_EMPTY_RESPONSE error is triggered by the http method after just 4 minutes ...

Vue.js component fails to load $refs

One of my Vue.js components features a modal view with various embedded references. <template> <div> <b-modal ref="modalDialog" > <b-row> <!-- document --> <b-col> &l ...

Tips for retrieving the final element from a corrupt JSON string using JavaScript

I've encountered an issue with a nodejs speech recognition API that provides multiple texts in a JSON like structure which renders the data invalid and useless. { "text": "Play" } { "text": "Play astronaut" } ...

Looking for a list of events in Express.js?

I've been searching through the official documentation, but I couldn't find a list of events for express. Does anyone know if there's something like 'route-matched' so that I can use app.on('route-matched', () => {})? ...

Is it possible to use the identical change function on numerous div elements?

How can functions be bound to multiple div elements effectively? $('#trigger1').change(function(){ // implement the code }); $('#trigger3').change(function(){ // execute the same code }); ...

VS Code sees JavaScript files as if they were Typescript

I have recently delved into the world of Typescript and have been using it for a few days now. Everything seems to be working smoothly - Emmet, linting, etc. However, I've encountered an issue when trying to open my older JavaScript projects in VS Cod ...

Experiencing difficulties when attempting to show or hide elements using jQuery

I spent several hours trying to figure this out and couldn't get it right. Is it feasible to create a jQuery script that will perform the following action when a <span> element is clicked: Check if any of the <p> elements are current ...

Is it necessary for the Jquery Component to return false?

I'm currently working on developing a jQuery module using BDD (Behavior-driven development). Below is the code snippet for my component: (function($) { function MyModule(element){ return false; } $.fn.myModule = function ...

Dealing with a Nodejs/Express and Angular project - Handling the 404 error

Recently, I decided to dive into learning the MEAN stack and thought it would be a great idea to test my skills by building an application. My goal was simple: display a static variable ('hello') using Angular in the HTML. However, I ran into an ...

When attempting to capture an element screenshot as PNG, a TypeError occurs indicating that the 'bytes' object is not callable

Can someone please help me figure out how to save a screenshot of a specific element in Selenium using Python3? Here is the code I am trying: from selenium import webdriver import pyautogui as pog import time options = webdriver.ChromeOptions() options ...

generate a series of nested divs within one another

I am looking to create a custom nested loop that will generate div elements based on the content of my h1 and h2/h3 tags. I understand this may have been covered in other inquiries, so any guidance would be appreciated :) Here is the initial HTML: <h1& ...

Utilizing Angular Filter to compare the date in a JSON file with the current system date

<p id="appt_time" ng-if="x.dateTime | date: MM/dd/yyyy == {{todaysDate}}">DISPLAY IF TRUE{{todaysDate}} </p> Plunkr:https://plnkr.co/edit/r2qtcU3vaYIq04c5TVKG?p=preview x.dateTime | date: MM/dd/yyyy retrieves a date and time which results in ...

JS The clipboardData in ClipboardEvent is perpetually void

I am trying to retrieve files using CTRL+V from the ClipboardEvent in Angular6, but I am encountering an issue where the clipboardData is always empty regardless of whether I test images or text. This problem persists even when tested on the latest release ...

What is the best way to incorporate an "if" statement into my code?

I'm in the process of setting up a section on my website where users can get live price estimates based on a value they input. While I have most of the formula in place, there's one final element that I need to figure out: introducing a minimum f ...