Cameron Scott
Cameron Scott

Reputation: 1306

Access-Control-Allow-Origin on a single Rails route

In my Rails app, I'm building a feature that allows users to embed data from the app on other sites using a Javascript snippet.

My Javascript snippet makes a GET request to a route in my rails app that returns raw JSON. When snippet and the JSON share the same domain, everything works well, but I'm running into CORS issues when I embed the snippet on another site.

Using the solution I found here, I've begun configuring my Rails app for CORS.

In my application_controller.rb:

before_filter :add_allow_credentials_headers

def add_allow_credentials_headers
    response.headers['Access-Control-Allow-Origin'] = request.headers['Origin'] || '*'   
    response.headers['Access-Control-Allow-Credentials'] = 'true'
end 

def options
    head :status => 200, :'Access-Control-Allow-Headers' => 'accept, content-type'
end

In my routes.rb:

get 'embed_json' => 'application#options', :via => [:options]

However, when I hit the above route in my browser, the app no longer returns the JSON object—just a blank screen.

There seem to be a number of conflicting approaches on how best to handle CORS on a single Rails route. Is there a "Rails way" to handle this requirement?

Upvotes: 9

Views: 6894

Answers (3)

Alex Onozor
Alex Onozor

Reputation: 7091

Install this gem:

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

Then add this to your config/application.rb file.

module YourApp
  class Application < Rails::Application

    # ...

    # Rails 3/4

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

    # Rails 5

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

  end
end

this will do the trick read more. Cors

Upvotes: 2

tekina
tekina

Reputation: 572

Add status: :ok to the raw JSON you are returning. In case you return an empty body, add head :ok to return a 200 status

To only enable CORS for options method, what you can do is:

before_filter :add_allow_credentials_headers, only: [:options]

def add_allow_credentials_headers
  response.headers['Access-Control-Allow-Origin'] = request.headers['Origin'] || '*' # the domain you're making the request from
  response.headers['Access-Control-Allow-Credentials'] = 'true'
  response.headers['Access-Control-Allow-Headers'] = 'accept, content-type'
end 

def options
  # your json response here or just 'head :ok' if empty 200 response
end

Upvotes: 2

Jeff Wigal
Jeff Wigal

Reputation: 708

A call to head won't return JSON by definition. The options hash, when you call it with head will be converted into headers.

Might try this instead, an options call will give the headers as needed with an empty response body. A call to index should render JSON, along with the headers you set in the add_allow_credentials_headers filter.

def add_allow_credentials_headers
  response.headers['Access-Control-Allow-Origin'] = request.headers['Origin'] || '*'   
  response.headers['Access-Control-Allow-Credentials'] = 'true'
  response.headers['Access-Control-Allow-Headers'] = 'accept, content-type'
end 

def options
  head :ok
end

def index
  # do something here that renders a JSON response
end

Also, another option for enabling CORS on your rails app is rack-cors, might do what you need without the hassle of doing it yourself.

Upvotes: 2

Related Questions