Here is a small deviation from your code:
# config/boot.rb
require 'rails/commands/server'
module DefaultOptions
PORT = 3001
def default_options
super.merge!(Port: PORT)
end
end
# This line was part of the Stack Overflow answer you quoted, and is important
# With newer Ruby versions, you can call `prepend` directly
Rails::Server.prepend(DefaultOptions)
This follows the Stack Overflow answer you quoted, with the exception of extracting the port to the constant DefaultOptions::PORT. Now note that there is nothing magical about the name of the module DefaultOptions, it simply defines a plain module that is then prepended to Rails::Server. You could have named it however you wanted. When the development server launches, a new Rails::Server object is instantiated, and at some point the default_options method is called on that object. Because of the use of prepend, the method lookup will first reach the method you defined in DefaultOptions. The super in that method simply calls the original un-prepended default_options defined in Rails::Server.
The reason why it is "hard" to get the values in default_options is because it is an instance method, meaning you can access it only on an instance of Rails::Server class, and we don't typically have a hold of the server object. You could access it like this:
# config/development.config
require 'rails/commands/server'
Rails::Server.new.default_options[:Port]
But I think this is an unnecessary dependency and object creation. The name Rails::Server also implies we may want to have just one object of this class, and I wouldn't instantiate server objects just to get a hold of their configuration hash. Therefore, extracting the port out to a constant you can hold regardless of whether you have a reference to a server object - DefaultOptions::PORT - is cleaner in my mind.
So, now that we got a hold of DefaultOptions::PORT constant, you can use it in your mailer:
# config/development.rb
config.action_mailer.smtp_settings = {
:port => DefaultOptions::PORT,
:address => '...',
:user_name => '...',
:password => '...',
:domain => '...',
:authentication => :plain
}
You could also consider having the mailer and port definition in a yaml file, so that you do not need to "sprinkle" parts of your configuration in different locations - it might save you some head banging later.
If you'd like to do this, you could create a wrapper class yourself that uses YAML.load_file to load your new yaml configuration file into a hash. Alternatively, check out Figaro gem, it gives a convenient way to place all Rails configurations in a single file - application.yml - and access them from everywhere using ENV.
If you were to use Figaro, for example, and have the PORT key in application.yml, then your code may look like this:
# config/boot.rb
require 'rails/commands/server'
module DefaultOptions
def default_options
super.merge!(Port: ENV['PORT'])
end
end
Rails::Server.prepend(DefaultOptions)
# config/development.rb
config.action_mailer.smtp_settings = {
:port => ENV['PORT'],
:address => ENV['SMTP_SERVER'],
:user_name => ENV['SMTP_LOGIN'],
:password => ENV['SMTP_PASSWORD'],
:domain => ENV['MAILER_DOMAIN'],
:authentication => :plain
}