I took a different approach than Jimmy in doing this same thing.
I deployed two apps on Heroku: a Rails API and a Create-React-App front end. Without getting too specific, there are a few keys for setting this up. First, in your rails api, edit the cors.rb file so that it allows cross-origin requests:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'localhost:3000', 'https://myapp.herokuapp.com'
resource '*',
headers: :any,
methods: [:get, :post, :put, :delete],
end
end
As this file implies, my rails app does not run on localhost:3000 locally, i changed it to run on port 8000 instead by editing puma.rb:
port ENV.fetch("PORT") { 8000 }
Create-react-app runs on localhost:3000 locally by default, so you can set your rails api to run on whatever port that you want, as long as it's different than your front-end.
I then made a file in my create-react-app that contains the API url and commonly used endpoints that I call AppConstants.js:
// let APIRoot = "http://localhost:8000";
let APIRoot = "https://my-rails-api.herokuapp.com";
export default {
APIEndpoints: {
LOGIN: APIRoot + "/users/login",
SIGNUP: APIRoot + "/users/create",
TODOS: APIRoot + "/todos",
ITEMS: APIRoot + "/items",
},
};
Now you edit your fetch/ajax/xmlHttpRequest calls so that the URL it uses references these routes. For example using fetch:
fetch(AppConstants.TODOS, {
method: 'POST',
body: JSON.stringify(values)
})
.then(response => response.text())
.then((body) => {
console.log(body);
});
This app constants file makes it easy to switch between a local api root and a production api root.
Deploy your rails api to heroku as you normally would, a suitable build pack will automatically be detected. For your react app, I suggest using this buildpack as will make a production build of your create-react-app and serve the static assets for you.