I often have many Rails apps running in parallel, so I have configured them to use different ports:
# Change default port of development server, see http://stackoverflow.com/questions/18103316
require 'rails/commands/server'
module DefaultOptions
def default_options
super.merge!(Port: 3001)
end
end
Now it's important that this also works for ActionMailer in development env:
config.action_mailer.default_url_options = {host: 'localhost:3001'}
But instead of hardcoding this, I'd like to set it directly from DefaultOptions
. How is this possible?
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
}
You can use the Rails::Server::Options to get the information you need and then configure the ActionMailer accordingly:
config.action_mailer.default_url_options = { host: Rails::Server.new.options[:Host], port: Rails::Server.new.options[:Port] }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With