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

我经常有许多并行运行的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) 

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

default_options获取值“难”的原因是因为它是一个实例方法,这意味着你只能在Rails::Server类的实例上访问它,而我们通常不会拥有服务器宾语。 您可以像这样访问它:

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

但我认为这是一种不必要的依赖和对象创建。 Rails::Server这个名字也暗示我们可能只想拥有这个类的一个对象,而且我不会实例化服务器对象只是为了获得它们的配置哈希。 因此,无论您是否具有对服务器对象的引用( DefaultOptions::PORT ,都可以将端口提取到常量,您可以更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 ,并在application.yml使用PORT键,那么您的代码可能如下所示:

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

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

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