For my deployment, I prefer to have all Rails configuration options in YML files under config/
. I am having particular problems with action_mailer.smtp_settings
.
I have a file, config/smtp.yml
:
development:
address: localhost
port: 1025
test:
production:
address: smtp.xs4all.nl
port: 465
authentication: plain
user_name: xxxxx
password: xxxxx
tls: true
I then try to include these values via an initializer. config/initializers/smtp.rb
:
options = YAML.load_file(Rails.root.join('config', 'smtp.yml'))[Rails.env]
options.each do |name, value|
Portfolio::Application.config.action_mailer.smtp_settings[name.to_sym] = value
end unless options.nil?
This loads the smtp.yml
file, parses that and returns the hash for the current environment, e.g.
{"address"=>"smtp.xs4all.nl", "port"=>465, "authentication"=>"plain", "user_name"=>"xxxxx", "password"=>"xxxxx", "tls"=>true}
Converts the keys to symbols and adds that to the smtp-settings, resuling in e.g:
irb(main):002:0> Portfolio::Application.config.action_mailer.smtp_settings
=> {:port=>465, :address=>"smtp.xs4all.nl", :authentication=>"plain", :user_name=>"xxxxx", :password=>"xxxx", :tls=>true}
But when deploying to production, this causes some conflict, probably because some part has not been booted yet. Capistrano fails with:
* executing "cd -- /var/www/ANT_cms/releases/20131218170336 && bundle exec rake RAILS_ENV=production RAILS_GROUPS=assets assets:precompile"
servers: ["li153-5.members.linode.com"]
[li153-5.members.linode.com] executing command
** [out :: li153-5.members.linode.com] rake aborted!
** [out :: li153-5.members.linode.com] undefined method `[]=' for nil:NilClass
Why is my Portfolio::Application.config.action_mailer.smtp_settings
nil here? How can I make sure that actionMailers config options are already loaded?
Digging deeper, I found the issue is that bundle exec rake RAILS_ENV=production RAILS_GROUPS=assets assets:precompile"
loads only a small subset, and not e.g. ActionMailer
.
Adding an early exit to my loader fixes this in config/initializers/smtp.rb
:
unless Portfolio::Application.config.action_mailer.nil?
options = YAML.load_file(Rails.root.join('config', 'smtp.yml'))[Rails.env]
options.each do |name, value|
Portfolio::Application.config.action_mailer.smtp_settings[name.to_sym] = value
end unless options.nil?
end
Then, the next issue is that action_mailer in production is set, but that smtp_settings does not have to be defined and filled with defaults, yet. So prefilling this with an empty hash solves the entire issue:
unless Portfolio::Application.config.action_mailer.nil?
Portfolio::Application.config.action_mailer.smtp_settings = {}
options = YAML.load_file(Rails.root.join('config', 'smtp.yml'))[Rails.env]
options.each do |name, value|
Portfolio::Application.config.action_mailer.smtp_settings[name.to_sym] = value
end unless options.nil?
end
Still, somewhat ugly, but it does the job.