简体   繁体   中英

React frontend POST / PUTS to Rails 5 API backend

I've got a Rails 5 API with a React frontend running in a /client directory. I'm trying to implement all of the CRUD actions for a resource via the React frontend. The React frontend is running on port 3000, and the Rails API backend is running on port 3001. I have CORS installed / enabled on Rails:

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'localhost:3001'

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

and in the React package.json I have:

"proxy": "http://localhost:3000",

My rails routes are:

Prefix Verb   URI Pattern         Controller#Action
  dogs GET    /dogs(.:format)     dogs#index
       POST   /dogs(.:format)     dogs#create
   dog GET    /dogs/:id(.:format) dogs#show
       PATCH  /dogs/:id(.:format) dogs#update
       PUT    /dogs/:id(.:format) dogs#update
       DELETE /dogs/:id(.:format) dogs#destroy

Current, I can successfully get and display a list of Dogs in React using:

window.fetch('dogs')
      .then(response => response.json())
      .then(json => this.setState({dogs: json}))
      .catch(error => console.log(error))
  }

However, I want to be able to edit each dog. So I have the following in a 'Dog' React component to handle updates:

handleSubmit(event) {
    event.preventDefault()
    let url = `dogs/${this.state.id}`
    let data = {
      dog: {
        id: this.state.id,
        name: this.state.name,
        age: this.state.age,
        sex: this.state.sex,
        description: this.state.description
      }
    }

    let updateDog = {
      method: 'PUT',
      body: data
    }
    fetch(url, updateDog)
      .then(json => console.log(json))
      .catch(error => console.log(error))
  }

(I'll use the response to set state eventually, however just logging it for now) In Chrome's console, when I submit the form I get the following error:

PUT http://localhost:3000/dogs/1 400 (Bad Request)
Dog.jsx:61 Response {type: "cors", url: "http://localhost:3000/dogs/1", redirected: false, status: 400, ok: false…}

But when I use Postman to submit the following PUT to http://localhost:3000/dogs/1 , it successfully updates the dog! What am I doing wrong?

{
  "id": 1,
  "name": "Lord Barkington",
  "age": 7,
  "sex": "M",
  "description": "Pieces of Eight jolly boat mutiny me cable spike Sail ho ho draught reef sails grapple schooner topsail Yellow Jack.",
}

I had the same issue with a different set up (PHP API and React in frontend). The reason for the error is that POST requests operate differently in this situation:

  1. Send a preflight request of type OPTIONS
  2. If it was successful send the actual POST request with the data

You can see practical examples on this in this blog post . Try to open your Chrome Console (network tab). There you will find both, the OPTIONS request and the POST request together with their content and responses.

Postman has a special behavior, not sending preflight requests (read it here ) which is why your browser test do not work even if postman does.

Solution

Make sure that your rails router accepts OPTIONS requests and returns a 200 OK.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM