11

I am using the rack-cors gem with a Rail 5.1 API.

I have the following initializer as per the documentation:

config/initializers/cors.rb

module Api
  Rails.application.config.middleware.insert_before 0, Rack::Cors do
    allow do
      origins ['http://localhost:4200','https://app.mydomain.com/']

      resource '*',
        headers: :any,
        :expose  => ['access-token', 'expiry', 'token-type', 'uid', 'client'],        
        methods: [:get, :post, :put, :patch, :delete, :options, :head]
    end
  end
end

However, this means that when deployed to production my api will accept requests from any localhost:4200 origin.

How can I separate these settings out so that different environments can have different allowed origins?

rmcsharry
  • 4,357
  • 4
  • 50
  • 87

2 Answers2

17

There are a few different options. One is to use secrets.yml file. There you can define different values per environment, let's say:

development:
  allowed_origins:
    - http://localhost:4200

production:
  allowed_origins:
    - http://productionurl1.com
    - http://productionurl2.com

Then in your configuration file you can do

module Api
  Rails.application.config.middleware.insert_before 0, Rack::Cors do
    allow do
      origins Rails.application.secrets.allowed_origins
    end
  end
end

Another option (taken from the comments) is to use the environment files, eg:

development.rb

config.allowed_cors_origins = ["http://localhost:4200"]

Then in the cors.rb initializer you can do:

Rails.application.config.allowed_cors_origins 

(since initializer will be called after the environment config file, this should work).

rmcsharry
  • 4,357
  • 4
  • 50
  • 87
Gregory Witek
  • 1,066
  • 7
  • 10
  • Thanks, that's a good idea. You mentioned other options - how would you use the already existing environment files? Surely that would be preferable, since these are environment related settings? – rmcsharry Apr 23 '18 at 16:58
  • 3
    If you want to use the environment config file, you can just write something like `config.allowed_cors_origins = ["http://localhost:4200"]` in `development.rb` file, and then in the `cors.rb` initializer you can do `origins Rails.application.config.allowed_cors_origins` - since initializer will be called after the environment config file, this should work. – Gregory Witek Apr 24 '18 at 09:54
  • The second option worked for me. I was using figaro gem for the environment variables, it kept throwing errors. setting the allowed origins on production/development.rb worked well though – Ndeto Oct 03 '19 at 09:59
5

For anyone using rails 5.2, secrets.yml has been changed and now we need to use credentials. In order to use that, we need to edit config/credentials.yml.enc First, run the command EDITOR="atom --wait" rails credentials:edit (using the editor of your choosing). Then, add the origins as the accepted answer suggests:

development:
  allowed_origins:
   - http://localhost:4200

production:
  allowed_origins:
   - http://productionurl1.com
   - http://productionurl2.com

Save the file. Now the allowed origins variables will be in the encrypted file. And then in the cors initializer (in my case it was in application.rb)

config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins Rails.application.credentials[Rails.env.to_sym][:allowed_origins]
    resource '*',
    headers: :any,
    expose: ['access-token', 'expiry', 'token-type', 'uid', 'client'],
    methods: [:get, :post, :options, :delete, :put]
  end
end
rmcsharry
  • 4,357
  • 4
  • 50
  • 87
gumlym
  • 805
  • 14
  • 26