Handling CORS between Rails API and React

977 Views Asked by At

I'm coding a Rest API using Ruby on Rails 6, I'm testing one of the endpoint (it's a GET Request) using Postman or Curl I'm getting the expected response; when I try to use my frontend (React) I'm getting a 200 response but the data is not fetched.

These pictures are from the firefox's console:

console1

This is the data sent from the backend:

console2

but in the DOM the data is not displayed it:

dom

All right, my frontend(localhost:3005) code looks like this:

  useEffect(() => {
    const fetchMeals = async () => {
      const response = await fetch("http://localhost:3000/meals.json", {
        'method': 'GET',
        'mode': 'no-cors',
        'headers': {
          'Origin': 'localhost:3000',
          'Access-Control-Allow-Origin': '*',
        }
      });
      //https://movieserp-default-rtdb.firebaseio.com/meals.json

      if (!response.ok) {
        throw new Error("The data could not be shown");
      }

      const responseData = await response.json(); 
      //el objeto se traduce a un array
      const loadedMeals = [];

      for (const key in responseData) {
        loadedMeals.push({
          id: key,
          name: responseData[key].name,
          description: responseData[key].description,
          price: responseData[key].price,
        });
      }

      //checking if the array is not null
      if (!loadedMeals.length) {
        throw new Error("No products found to display");
      } else {
        setMeals(loadedMeals);
        setIsLoading(false);
      }
    };

    fetchMeals().catch((error) => {
      setIsLoading(false);
      setHttpError(error.message);
    });
  }, []);

and this is the backend (localhost:3000) code (config/initializers/cors.rb:

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

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

Bellow you can find the controller's source code:

class MealsController < ApplicationController
    #get /meals
    def index
        @meals = Meal.all
        render json: @meals
    end
end

And finally the model:

class Meal < ApplicationRecord

    def as_json(options = {})
        super(:only => [:id, :name, :description, :price])
    end
    
end

In the browser's console (Firefox) I got status 200 and the response looks like this:

[
    {
        "id": 1,
        "name": "Cheese and Loroco",
        "description": "Corn made pupusa with cheese",
        "price": "1.25"
    },
    {
        "id": 2,
        "name": "Cheese and red deans",
        "description": "Corn made pupusa with cheese and beans",
        "price": "0.65"
    },
    {
        "id": 3,
        "name": "Pork, cheese and red beans",
        "description": "Corn made pupusa with a mix of pork,cheese and red beans",
        "price": "0.85"
    },
    {
        "id": 4,
        "name": "Soda",
        "description": "Salvadoran soda beverages",
        "price": "0.65"
    },
    {
        "id": 5,
        "name": "Coffee",
        "description": "High quality roasted salvadoran coffee",
        "price": "1.1"
    }
]

However, the data is not displayed in the DOM, in fact, the fetch object (response) is null.

My questions are:

  1. I'm getting the data from the backend (it is displayed in the browser's console)
  2. Why in the frontend the object (response) is null?
  3. response.ok is equals to false, if I got a 200 response, why I'm not getting the data in json format to the front end?

I really will appreciate your comments or guidance about it.

thanks a lot

1

There are 1 best solutions below

6
On

Add GemFile: gem 'rack-cors'

Add application.rb

config.middleware.insert_before 0, Rack::Cors do
  allow do
     origins '*'
     resource '*', :headers => :any, :methods => [:get, :post, :patch, :put, :delete]
   end
end
class MealsController < ApplicationController
    //path: http://localhost:3000/meals.json
    def index
        @meals = Meal.all
        respond_to do |format|
         format.html
         format.json {render json: @meals}
        end
    end
end

or

class MealsController < ApplicationController
    //path: http://localhost:3000/meals
    def index
        @meals = Meal.all
        render json: @meals
    end
end