19

I am trying to use Rack::Cors with my Rails 4 application so that I can do a JSON based API.

CORS is in my Gemfile like this:

gem 'rack-cors', :require => 'rack/cors'

I am doing the configuration in my application.rb file like this:

config.middleware.insert_after Rails::Rack::Logger, Rack::Cors, :debug => true, :logger => Rails.logger do
    allow do
        origins '*'
        resource '/messages*', :headers => :any, :methods => [:post, :options]
    end
end

I am inserting after Rails::Rack::Logger in an attempt to get debugging information.

I am using CURL to test it, here is what I have been running:

curl --verbose --request OPTIONS http://jasonbutzinfo.herokuapp.com/messages.json --header 'Origin: http://www.jasonbutz.info' --header 'Access-Control-Request-Headers: Origin, Accept, Content-Type' --header 'Access-Control-Request-Method: POST'

When I run the rails app on my local machine it works without issue. When I hit the Heroku app this is what I get:

> OPTIONS /messages.json HTTP/1.1
> User-Agent: curl/7.30.0
> Host: jasonbutzinfo.herokuapp.com
> Accept: */*
> Origin: http://www.jasonbutz.info
> Access-Control-Request-Headers: Origin, Accept, Content-Type
> Access-Control-Request-Method: POST
> 
* Empty reply from server
* Connection #0 to host jasonbutzinfo.herokuapp.com left intact
curl: (52) Empty reply from server

I did find this question (Can't get rack-cors working in rails application), but there wasn't any helpful answer provided.

Update 11/13/2013 16:40 EST

I've been trying to do some more debugging with what is going on. I have monkey patched a few of Rack::Cors' methods to see if they are even being called on Heroku. I have also changed where I insert Cors to be at the top of the rack middleware stack.

With my monkey patching I have put puts statements in the initialize, call, and allow methods. The initialize and allow methods are both called. The call method is never called. So it seems there is something that is stopping the request before it gets to the cors middleware.

Community
  • 1
  • 1
Jason
  • 1,114
  • 1
  • 10
  • 24
  • Did you ever figure this out? I have been having it intermittently work.... Can't figure out how to debug it on heroku at all though. :( – Mark G. Dec 05 '13 at 06:40
  • @Mark37 I still haven't figured this out. – Jason Dec 05 '13 at 19:50
  • I swear I just had it working yesterday. Interestingly the heroku logs are not even registering my OPTIONS requests, so I filed a support ticket and will see if there's something going on with the heroku router. I'll post back if I hear anything. – Mark G. Dec 05 '13 at 19:53
  • 1
    Also weird fact, if my service has spun down due to idling, and I try to issue that curl OPTIONS request, the dyno won't start again. It's only if I issue GET,POST,PUT,DELETE that the dyno starts spinning up. – Mark G. Dec 06 '13 at 15:56

6 Answers6

15

I ran into the same problem with heroku. I found this blog with the same rack-cors issue.

Just moved the use Rack::Cors to config.ru, redeployed to heroku and it works.

require ::File.expand_path('../config/environment',  __FILE__)
run Rails.application

require 'rack/cors'
use Rack::Cors do

  # allow all origins in development
  allow do
    origins '*'
    resource '*', 
        :headers => :any, 
        :methods => [:get, :post, :delete, :put, :options]
  end
end
dcunited001
  • 501
  • 3
  • 6
4

It looks like the issue is being caused by my machine or the network I am on. I SSHed into a hosting environment I use and used the curl command above and it worked.

Additional Note Here is something else that just happened that I thought I ought to add to this. My AJAX request was not to the https URL for my Heroku app, but Heroku was translating it be https. This was causing an additional cross-origin issue. Switching to use https for the AJAX request fixed this.

Jason
  • 1,114
  • 1
  • 10
  • 24
  • I can confirm that this is also the case for me - but I really want to know why as this makes it impossible to use my webapp from this particular network. – Mark G. Dec 09 '13 at 23:04
2

Ok thanks to Jason I was able to figure out the root cause for me. I had the Cisco AnyConnect VPN client installed and it was blocking CORS requests.

You can find out more here: http://www.bennadel.com/blog/2559-Cisco-AnyConnect-VPN-Client-May-Block-CORS-AJAX-OPTIONS-Requests.htm

Uninstalling it all of a sudden allowed everything to work!

Mark G.
  • 3,176
  • 1
  • 27
  • 29
  • This was totally our issue! Computers without VPN were fine & those with were having issues. Our default system image installs it, so we had to manually kill it too. Thank you so much, Mark37 :-) – Abel Jul 29 '14 at 17:47
1

I was having a similar problem, I could not read Location header from the response in angularjs, even though I could see it in chrome's dev tools. I had the Rack::Cors set like this:

config.middleware.insert_before "ActionDispatch::Static", "Rack::Cors" do
    allow do
        origins '*'
        resource '*',
            headers: :any,
            methods: [:get, :post, :delete, :put, :patch, :options, :head],
            max_age: 0
        end
    end

The solution for me was to add the location to the :expose option, and after that I could see it in angularjs:

config.middleware.insert_before "ActionDispatch::Static", "Rack::Cors" do
    allow do
        origins '*'
        resource '*',
            headers: :any,
            methods: [:get, :post, :delete, :put, :patch, :options, :head],
            max_age: 0,
            expose: :location
        end
    end
bosskovic
  • 2,034
  • 1
  • 14
  • 29
0

Try

config.middleware.insert_before ActionDispatch::Static, Rack::Cors do
  # ...
end
Mark S.
  • 1,082
  • 1
  • 12
  • 22
0

If you are using Rails 6:

First go to your Gemfile and uncomment gem 'rack-cors'. Then run bundle install

After that go to config/initializers folder. There, you should find a file called cors.rb.

Uncomment the code that looks like this

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'example.com'

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

change the line that says origins 'example.com' to origin '*' or if you're request will be originating from a particular origin, then set it accordingly.

This worked for me. Hope it works for you as well. Cheers

Phillip Musiime
  • 167
  • 2
  • 12