Reputation: 1306
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
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
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
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