我经常有许多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进行设置。这怎么可能?

最佳答案

这与您的代码略有不同:

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

除了将端口提取到常量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
}

09-26 05:10
查看更多