Handling CORS in Rails for client side apps
Building a client side app with React is a bliss, just like building backend with Ruby on Rails. In React if you make an api to call to backend you would get an error like so.
Response to preflight request doesn’t pass access control check: No \
‘Access-Control-Allow-Origin’ header is present on the requested resource. \
Origin ‘http://localhost:4000' is therefore not allowed access. The response had \
HTTP status code 404. If an opaque response serves your needs, set the request’s \
mode to ‘no-cors’ to fetch the resource with CORS disabled.
CORS or Cross Origin Resource Sharing gives web server cross domain access control, which enables secure cross-domain data transfers. Browsers use CORS in an API container, such as XMLHttpRequest (what Axios and Fetch use under the hood), to mitigate the risks of cross-origin HTTP requests.
To fix this, we have 2 options.
- Set request mode to 'no-cors' to fetch the resource with CORS disabled, this will return an opaque response.
- Add an ‘Access-Control-Allow-Origin’ header to rails server.
If we set 'no-cors' it returns the following Opaque response.
Response {
body: null
bodyUsed: false
headers: Headers
ok: false
redirected: false
status: 0
statusText: ""
type: "opaque"
url: ""
}
There are a couple of things to note:
- the
status
is "0" (and not a regular HTTP status code - like 200) - the
statusText
is empty - the
headers
object is also empty
Basically, we can't see anything in this Response
object - and henceforth the name opaque. Opaque response or 'no-cors' mode can be used with <script>
, <img>
, <video>
, <audio>
, <link rel="stylesheet">
, <object>
, <embed>
and <iframe>
elements.
So it's of no use to us, given that we need the data from our rails api. We need to add the Access-Control-Allow-Origin
header to the rails server. We can use this wonderful gem rack-cors. We need to add the gem to our Gemfile.
gem 'rack-cors'
And add the following config in config/application.rb
file
module YourApp
class Application < Rails::Application
# ...
# Rails 5
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post, :options]
end
end
# Rails 3/4
config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post, :options]
end
end
end
end
That's about it, no more CORS issue. 🚀 We are good to go.