freezes on :options... do I need a route for this? #20

Closed
dfl opened this Issue Mar 6, 2013 · 5 comments

Comments

Projects
None yet
4 participants
@dfl

dfl commented Mar 6, 2013

I am new to this, and it would be great if you could provide an example route and/or controller action on how to serve options in Rails. thanks!

@nashby

This comment has been minimized.

Show comment Hide comment
@nashby

nashby Oct 19, 2013

Yeah, you can use something like this to add OPTIONS support for your route:

match :foo, via: [:get, :options], controller: 'users'

(I know it was 8 months ago but still)

nashby commented Oct 19, 2013

Yeah, you can use something like this to add OPTIONS support for your route:

match :foo, via: [:get, :options], controller: 'users'

(I know it was 8 months ago but still)

@monfresh

This comment has been minimized.

Show comment Hide comment
@monfresh

monfresh Jun 19, 2014

@dfl Here is how I got it to work in Rails 4.0:

# config/application.rb
config.middleware.use Rack::Cors do
  allow do
    origins '*'
    resource '*', headers: :any, methods: [:get, :put, :patch, :post]
  end
end
# config/routes.rb
match '/locations' => 'locations#render_204', via: [:options]
match '/locations/:id' => 'locations#render_204', via: [:options]
# app/controllers/locations_controller.rb
def render_204
  head 204
end

With that in place, I can now issue an OPTIONS request like so:

curl -i http://www.lvh.me:8080/api/locations/1 -H "Origin: http://example.com" -X OPTIONS

And I get the correct headers in the response:

Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET, PUT, PATCH, POST
Access-Control-Expose-Headers:
Access-Control-Max-Age: 1728000
Access-Control-Allow-Credentials: true

If you have many resources and routes that need to be able to respond to an OPTIONS request, you can create a separate controller that just defines the render_404 method. For example:

# app/controllers/cors_controller.rb
class CorsController < ApplicationController
  def render_204
    head 204
  end
end

Then send all requests to that controller:

# config/routes.rb
match '*foo' => 'cors#render_204', via: [:options]

@cyu Does this look right to you? If so, I think it should be documented in this repo as it's not obvious to CORS beginners. I'd be happy to submit a PR for a README update, or I can add a Wiki page.

@dfl Here is how I got it to work in Rails 4.0:

# config/application.rb
config.middleware.use Rack::Cors do
  allow do
    origins '*'
    resource '*', headers: :any, methods: [:get, :put, :patch, :post]
  end
end
# config/routes.rb
match '/locations' => 'locations#render_204', via: [:options]
match '/locations/:id' => 'locations#render_204', via: [:options]
# app/controllers/locations_controller.rb
def render_204
  head 204
end

With that in place, I can now issue an OPTIONS request like so:

curl -i http://www.lvh.me:8080/api/locations/1 -H "Origin: http://example.com" -X OPTIONS

And I get the correct headers in the response:

Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET, PUT, PATCH, POST
Access-Control-Expose-Headers:
Access-Control-Max-Age: 1728000
Access-Control-Allow-Credentials: true

If you have many resources and routes that need to be able to respond to an OPTIONS request, you can create a separate controller that just defines the render_404 method. For example:

# app/controllers/cors_controller.rb
class CorsController < ApplicationController
  def render_204
    head 204
  end
end

Then send all requests to that controller:

# config/routes.rb
match '*foo' => 'cors#render_204', via: [:options]

@cyu Does this look right to you? If so, I think it should be documented in this repo as it's not obvious to CORS beginners. I'd be happy to submit a PR for a README update, or I can add a Wiki page.

@cyu

This comment has been minimized.

Show comment Hide comment
@cyu

cyu Jun 19, 2014

Owner

@monfresh this looks great - yes a PR would be great!

Owner

cyu commented Jun 19, 2014

@monfresh this looks great - yes a PR would be great!

@cyu

This comment has been minimized.

Show comment Hide comment
@cyu

cyu Sep 7, 2014

Owner

This issues is a duplicate of #44

Owner

cyu commented Sep 7, 2014

This issues is a duplicate of #44

@cyu

This comment has been minimized.

Show comment Hide comment
@cyu

cyu Oct 14, 2014

Owner

Ok, reviewing this issue in context #57, there does seem to be an issue here, but it's not what you'd expect.

The issue as I see it is that non-preflight OPTIONS requests are returning CORS headers when they shouldn't be. The curl command @monfresh used in his example isn't a valid Preflight request (it's missing the Access-Control-Request-Method header which is required for Preflight). That request should be treated as a non-CORS request and not return those headers at all.

I'm going to create a new issue and close this one.

Owner

cyu commented Oct 14, 2014

Ok, reviewing this issue in context #57, there does seem to be an issue here, but it's not what you'd expect.

The issue as I see it is that non-preflight OPTIONS requests are returning CORS headers when they shouldn't be. The curl command @monfresh used in his example isn't a valid Preflight request (it's missing the Access-Control-Request-Method header which is required for Preflight). That request should be treated as a non-CORS request and not return those headers at all.

I'm going to create a new issue and close this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment