Search code examples
ruby-on-railscorsamazon-cloudfront

Rails + AWS CloudFront + CORS for AngularJS HTML templates


I am deploying a Rails 4 application using AngularJS as our front-end MVC framework, and I'd like to deploy our assets through a CDN. After running into issues with getting the properly fingerprinted URLs when calling asset_path within my AngularJS routing javascript file, I decided to eliminate the AssetSync gem. To replace AssetSync, I would like to simply use Amazon CloudFront on top of my Rails server serving its own static assets. This works great for my CSS and JS files, but unfortunately I run into CORS issues when trying to serve my HTML templates for Angular as assets:

Chrome Dev Tools console output

Any ideas would be much appreciated!

UPDATE 4/30:

I was finally able to get my Rails server to set the proper 'Access-Control-Allow-Origin' header on assets with the rack-cors gem by following the instructions in this Github issue. Now when I run curl to fetch the files from CloudFront, I see the proper headers. However, when I run curl to send an OPTIONS request, I'm still getting a 403 Forbidden. Check out the two screenshots below:

The GET request for the asset looks good:

Curl GET Request

But the OPTIONS request doesn't....

Curl GET Request


Solution

  • I've been asked for this solution a couple times, so I thought I would post what worked for us here.

    It seems that Rails will set the CORS headers correctly for CSS and JS files only. However, you can use the rack-cors gem to set custom headers for resources. We added the following configuration to our config/application.rb:

    config.middleware.insert_before 0, "Rack::Cors" do
        allow do
            origins '*'
            resource '/assets/*', :headers => :any, :methods => [:get, :options]
        end
    end
    

    We were able to set the CORS headers on only our assets because our asset prefix was set to /assets with the following (default) line in our config/environments/production.rb:

    config.assets.prefix = "/assets"
    

    To complete the AWS CloudFront configuration, follow @Cfstat's advice in his answer and make sure that you've edited the default cache behavior on AWS CloudFront to enable extended verb support. Set Allowed HTTP Methods to include GET and OPTIONS.

    The last bit of configuration to get all of this working is to set your asset host to point to AWS CloudFront. We wanted to use an environment variable, so we used the following line in config/environments/production.rb:

    config.action_controller.asset_host = "//#{ENV['ASSET_HOST']}"
    

    Then we just set the ASSET_HOST env variable to point to our CloudFront URL.