ActionMailer的default_url_options:如何从DefaultOptions自动检索端口?

时间:2015-04-03 11:26:11

标签: ruby-on-rails

我经常并行运行许多Rails应用程序,所以我将它们配置为使用不同的端口:

# 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

现在重要的是,这也适用于开发环境中的ActionMailer:

config.action_mailer.default_url_options = {host: 'localhost:3001'}

但我不是硬编码,而是直接从DefaultOptions设置它。这怎么可能?

2 个答案:

答案 0 :(得分:1)

以下是与您的代码的小偏差:

# 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)

这是在您引用的Stack Overflow答案之后,但将端口提取到常量DefaultOptions::PORT除外。现在请注意,模块DefaultOptions的名称没有任何神奇之处,它只是定义了一个普通模块,然后将其添加到Rails::Server之前。你可以根据需要命名它。启动开发服务器时,会实例化一个新的Rails::Server对象,并且在某个时刻会在该对象上调用default_options方法。由于使用prepend,方法查找将首先到达您在DefaultOptions中定义的方法。该方法中的super只会调用default_options中定义的原始未加前导Rails::Server

之所以这么辛苦"获取default_options中的值是因为它是一个实例方法,这意味着您只能在Rails::Server类的实例上访问它,而我们通常不会拥有服务器对象。您可以像这样访问它:

# config/development.config
require 'rails/commands/server'
Rails::Server.new.default_options[:Port]

但我认为这是一种不必要的依赖和对象创建。名称Rails::Server也意味着我们可能只想拥有此类的一个对象,并且我不会实例化服务器对象只是为了获取其配置哈希值。因此,无论您是否具有对服务器对象的引用 - DefaultOptions::PORT - 都可以将端口提取到一个常量,您可以更清楚。

所以,既然我们保持DefaultOptions::PORT常数,你可以在你的邮件中使用它:

# config/development.rb
  config.action_mailer.smtp_settings = {
  :port => DefaultOptions::PORT,
  :address => '...',
  :user_name => '...',
  :password => '...',
  :domain => '...',
  :authentication => :plain
}

您还可以考虑将邮件程序和端口定义放在yaml文件中,这样您就不需要"撒上"您在不同位置配置的部分内容 - 它可能会为您节省一些时间。

如果您想这样做,您可以自己创建一个包装类,使用YAML.load_file将新的yaml配置文件加载到哈希中。或者,查看Figaro gem,它提供了一种方便的方法将所有Rails配置放在一个文件中application.yml - 并使用ENV从任何地方访问它们。

例如,如果您使用Figaro并在PORT中使用application.yml密钥,那么您的代码可能如下所示:

# 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
}

答案 1 :(得分:0)

您可以使用Rails::Server::Options获取所需信息,然后相应地配置ActionMailer:

config.action_mailer.default_url_options = { host: Rails::Server.new.options[:Host], port: Rails::Server.new.options[:Port] }