Reputation: 5667
In my config/application.rb
file, I have this code,
config.action_dispatch.default_headers = {
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => 'GET, PATCH, PUT, POST, OPTIONS, DELETE'
}
But that does not allow me to send a post request to a route on my sever
Safari gives this error:
http://localhost:3000/studentsFailed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:3000/studentsFailed to load resource: Origin http://localhost:4200 is not allowed by Access-Control-Allow-Origin.
localhost:1XMLHttpRequest cannot load http://localhost:3000/students. Origin http://localhost:4200 is not allowed by Access-Control-Allow-Origi
And in my Rails server console:
Started OPTIONS "/students" for ::1 at 2015-03-28 21:00:45 -0500
ActionController::RoutingError (No route matches [OPTIONS] "/students"):
Upvotes: 15
Views: 27493
Reputation: 26972
I spent some time working on this and I can tell you the most reliable solution is to use rack-cors. see: https://github.com/cyu/rack-cors
First add the gem:
gem 'rack-cors', '~> 0.3.1'
then in application.rb
add
config.middleware.insert_before ActionDispatch::Static, Rack::Cors do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :options]
end
end
If your production app does not serve static assets (such as if you use a serve like nginx or apache), consider replacing ActionDispatch::Static
in the above example with 0
. See https://github.com/cyu/rack-cors#common-gotchas for more information about the argument.
Upvotes: 23
Reputation: 1663
Rails 5
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post, :options]
end
end
Upvotes: 1
Reputation: 5667
I was able to figure this out with a bit of help from @Akiomi's answer:
In my routes.rb
, I added the following code to the top of the file:
match '(:anything)' => 'application#nothing', via: [:options]
Next, in my application controller, I added:
def nothing
render text: '', content_type: 'text/plain'
end
Along with the headers in config/application.rb
:
config.action_dispatch.default_headers = {
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => 'GET, PATCH, PUT, POST, OPTIONS, DELETE',
'Access-Control-Allow-Headers:' => 'Origin, X-Requested-With, Content-Type, Accept'
}
Yes, notice the 'Access-Control-Allow-Headers:' => 'Origin, X-Requested-With, Content-Type, Accept'
that was not included in my original question, this is one of the big problems.
Upvotes: 7
Reputation: 71
Add the following code:
In config/routes.rb
:
match 'students' => 'students#option', via: [:options]
In controllers/student_controller.rb
:
def option
render text: '', content_type: 'text/plain'
end
Or you can use rack-cors.
Upvotes: 2
Reputation: 84182
In some cases a browser will do a preflight request: rather than actually doing the request it first does an OPTIONS request to the same url, so that it can find out what the values of the various CORS headers are (More on preflighting here). If this request is successful and the headers have the correct values, it then does the actual request.
You haven't added a route for these options requests, so they're going through to the rails 404 page which doesn't include the CORS headers.
The OPTIONS response just needs to set the same CORS headers as you would normally set during a request. It shouldn't do anything else. For example
match 'students' => 'students#cors_preflight', via: [:options]
def cors_preflight
render nothing: true
end
Note that there are other CORS headers you may need to set such as Access-Control-Allow-Credentials
, Access-Control-Allow-Headers
When you've got this working you may wish to consider tightening this up a little - you are potentially opening your app to cross site scripting attacks.
Upvotes: 1