Rails Responds with 404 on CORS Preflight Options Request
Solution 1
Here's a solution with the rack-cors gem, which you said you tried. As others have mentioned, you didn't give much detail in regards to which front-end framework you're using and what the actual request looks like. So the following may not apply to you, but I hope it helps someone.
In my case, the gem worked fine until I used PUT (or PATCH or DELETE).
If you look in your browser developer console, look at the request headers, and you should have a line like this:
Access-Control-Request-Method: PUT
The important thing to note is that the methods
you pass to resource
are for the Access-Control-Request-Method
, not the Request Method that is to come after the pre-flight check.
Note how I have :methods => [:get, :post, :options, :delete, :put, :patch]
that will include all the methods I care about.
Thus your entire config section should look something like this, for development.rb
:
# This handles cross-origin resource sharing.
# See: https://github.com/cyu/rack-cors
config.middleware.insert_before 0, "Rack::Cors" do
allow do
# In development, we don't care about the origin.
origins '*'
# Reminder: On the following line, the 'methods' refer to the 'Access-
# Control-Request-Method', not the normal Request Method.
resource '*', :headers => :any, :methods => [:get, :post, :options, :delete, :put, :patch], credentials: true
end
end
Solution 2
Working on Rails 3.2.11.
I put
match '*path', :controller => 'application', :action => 'handle_options_request', :constraints => {:method => 'OPTIONS'}
in my routes.rb file. The key was to put it as top priority (on top of the routes.rb file). Created that action so that it is publicly available:
def handle_options_request
head(:ok) if request.request_method == "OPTIONS"
end
And a filter in application controller:
after_filter :set_access_control_headers
def set_access_control_headers
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE'
end
Solution 3
Yes, as others have pointed out there is a GEM to maybe do this better. But since I very much liked the method pointed out in the original blog post with the cors code, I've found the Rails 4 solution if you're using that code.
In your routes.rb:
match '*all' => 'my_method_name#cor', via: :options
In your my_method_name controller:
def cor
# blank section for CORR
render :text => ''
end
As long as you have that plus your other code:
before_filter :cors_preflight_check
after_filter :cors_set_access_control_headers
...
Then you should be set for Rails 4.
Solution 4
Perhaps this gist can help you: CORS in Rails 4 APIs
It adds the OPTIONS
method to the route definition, and adds a filter to the API base controller which directly responds to OPTIONS
requests with the correct header, and sets the correct CORS headers for all other actions, too.
Solution 5
I ran into the same issue, and am currently evaluating the following routes for any possible security / performance issues. They solve the issue, but...
match '/', via: [:options],
to: lambda {|env| [200, {'Content-Type' => 'text/plain'}, ["OK\n"]]}
match '*unmatched', via: [:options],
to: lambda {|env| [200, {'Content-Type' => 'text/plain'}, ["OK\n"]]}
Despite 'match' supposedly not working in Rails 4, apparently it does work if you restrict it to a specific method.
Related videos on Youtube
![Rolandus](https://i.stack.imgur.com/Ibi1K.jpg?s=256&g=1)
Rolandus
Updated on July 09, 2022Comments
-
Rolandus almost 2 years
I'm creating a set of services using Rails 4, which I am consuming with a JavaScript browser application. Cross-origin GETS are working fine, but my POSTs are failing the preflight OPTIONS check with a 404 error. At least, I think that's what's happening. Here are the errors as they appear in the console. This is Chrome 31.0.1650.63 on a Mac.
OPTIONS http://localhost:3000/confessor_requests 404 (Not Found) jquery-1.10.2.js:8706 OPTIONS http://localhost:3000/confessor_requests No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. jquery-1.10.2.js:8706 XMLHttpRequest cannot load http://localhost:3000/confessor_requests. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. main.html:1
I've searched high and low for instructions on enabling CORS, and I'm stumped. The usual recommendation seems to be to put something like this in the Application controller, which I did.
before_filter :cors_preflight_check after_filter :cors_set_access_control_headers def cors_set_access_control_headers headers['Access-Control-Allow-Origin'] = '*' headers['Access-Control-Allow-Methods'] = 'POST, PUT, GET, OPTIONS' headers['Access-Control-Allow-Headers'] = '*' headers['Access-Control-Max-Age'] = "1728000" end def cors_preflight_check if request.method == :options headers['Access-Control-Allow-Origin'] = '*' headers['Access-Control-Allow-Methods'] = 'POST, PUT, GET, OPTIONS' headers['Access-Control-Allow-Headers'] = '*' headers['Access-Control-Max-Age'] = '1728000' render :text => '', :content_type => 'text/plain' end end
Followed by some kind of route in routes.rb that will redirect to this action when an OPTIONS request comes in.
match "/*all" => "application#cors_preflight_check", :constraints => { :method => "OPTIONS" }
The 'match' directive no longer works in Rails 4, so I fiddled with it, attempting to make it match POSTS directly, like this:
post "/*all" => "application#cors_preflight_check", :constraints => { :method => :options }
But it still doesn't work. Since the GET requests are working, I'm assuming that what I'm missing is the correct route for the OPTIONS request. However, I've tried every route I can think of, and nothing seems to let the request through.
I also tried installing cyu/rack-cors, and this gives the same result.
Anyone know what I'm doing wrong?
-
Matt Jones over 10 years
match
should still work, but it complains if you don't pass avia
option. Doing it withpost
is definitely not going to work. As somebody who made this exact mistake before withrack-cors
, I'm also going to ask: did you restart the server after configuring therack-cors
middleware? I spent an hour+ chasing that a while back myself. :) -
collimarco over 8 yearsSame here. I've tried both the custom methods and the gem: everything works fine until an
ActiveRecord::RecordNotFound
exception is raised. In that case CORS doesn't work. -
collimarco over 8 yearsI have further investigated the issue: in my case the preflight response headers are correct, while the actual request (when an exception is raised) produces a response without the CORS headers
-
-
dmur almost 10 yearsThis answer is for Rails 3, but the question is specifically about Rails 4.
-
mpowered over 9 yearsI'm not sure implementing a proxy server is really an answer to this. What if someone else wants to interact with your API? Don't you think Rails should respond properly to the options request?
-
po3t over 9 years@AdamRobertson - You're probably right. My solution is not for publicly consumed APIs if anything other than GET requests are required. This solution should only be used for private APIs. That said, I was running into this problem regardless of what I did on the Rails end. No matter what kind of CORS solution I implemented, I would always make an OPTIONS request if I made anything other than a GET request. Chalk it up to lack of experience with Rails on my end.
-
Sebastialonso over 9 years@ancajic Thanks for your answer. Is there any security implication with this that you know of?
-
AndroC over 9 years@Sebastialonso... Obviously it can cause problems if your HTTP API has endpoints that respond to requests with method=OPTIONS. Other than that, I don't see any security implications that would not occur already by enabling CORS. More experienced Rails developers might be of more help ;)
-
Yahor Zhylinski over 8 yearsThanks. You saved my day:)
-
rramsden almost 8 yearsNice solution, instead of setting the headers manually in the application controller I set them per environment. For development in
config/environments/development.rb
you can configureconfig.action_dispatch.default_headers = {}
to include the COR headers. -
Hendrik over 7 yearsNot 100% sure where I had copied my rules from, some other SO post. But in this case adding the
put
made things work again. -
Dorian over 7 yearsSame, with js
fetch()
,method: "PATCH"
didn't work butmethod: "PUT"
worked (both used theAccess-Control-Request-Method
) -
Stéphane Bruckert almost 7 years
:patch
was missing from the CORS allowed methods! thanks -
Ken Ratanachai S. over 5 yearsThanks!. credentials: true Saved my day!
-
Bhawan over 4 yearsDon't we need to change anything in routes.rb file?
-
akostadinov almost 3 yearsThanks,
match
withto: lambda
. Some docs: apidock.com/rails/v6.0.0/ActionDispatch/Routing/Mapper/Base/…