I have been trying (unsuccessfully) to access the main app's application secrets from within my Rails mountable engine. The whole point of a mountable engine is to provide modularity. Therefore a common pattern would be to provide configurable parameters, some of which need to be secret, in the main app, which would then be used by the engine.
In my specific case, I am using carrierwave
and fog
in my engine to upload files to an AWS bucket. The exact bucket and AWS credentials are not specified in the engine, but in the main app, since they will vary providing which app is mounting the engine.
However, the initializer for carrierwave when mounted in the engine fails as it cannot find the Rails.application.secrets for the main app:
require 'carrierwave'
require 'carrierwave/storage/fog'
CarrierWave.configure do |config|
config.fog_provider = 'fog/aws'
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => Rails.application.secrets.S3_AWS_ACCESS_KEY_ID,
:aws_secret_access_key => Rails.application.secrets.S3_AWS_SECRET_ACCESS_KEY
}
config.fog_directory = Rails.application.secrets.CARRIERWAVE_CONFIG_FOG_DIRECTORY
config.storage = :fog
end
This fails when engine is started with
Missing required arguments: aws_access_key_id, aws_secret_access_key (ArgumentError)
as in fact Rails.application.secrets.S3_AWS_ACCESS_KEY_ID
(and the others) evaluates to nil
in the initializer. It does evaluate correctly inside the engine's controllers once the app is running, but in the initializer it is nil.
I have modified this like the following:
:aws_access_key_id => Rails.application.secrets.S3_AWS_ACCESS_KEY_ID || ENV["S3_AWS_ACCESS_KEY_ID"]
and exported the ENV VARIABLE in each production environment for use with the engine, but this is less than ideal. Any solution would be appreciated.
# config/initializers/engine_name.rb
EngineName.configure do |config|
config.aws_access_key_id = nil
config.aws_secret_access_key = nil
config.fog_directory = nil
end
# config/initializers/engine_name.rb
EngineName.configure do |config|
config.aws_access_key_id = Rails.application.secrets.S3_AWS_ACCESS_KEY_ID
config.aws_secret_access_key = Rails.application.secrets.S3_AWS_SECRET_ACCESS_KEY
config.fog_directory = Rails.application.secrets.CARRIERWAVE_CONFIG_FOG_DIRECTORY
end
# engine_name/config/initializers/carrierwave.rb
require 'carrierwave'
require 'carrierwave/storage/fog'
CarrierWave.configure do |config|
config.fog_provider = 'fog/aws'
config.fog_credentials = {
provider: 'AWS',
aws_access_key_id: EngineName.configuration.aws_access_key_id,
aws_secret_access_key: EngineName.configuration.aws_secret_access_key
}
config.fog_directory = EngineName.configuration.fog_directory
config.storage = :fog
end
By using this approach, you allow the main app to provide the necessary secrets through the engine's configuration, which avoids the issue of accessing the main app's secrets directly from the engine.