【问题标题】:How does Rails.application.configure block works without providing a variable nameRails.application.configure 块如何在不提供变量名的情况下工作
【发布时间】:2018-01-22 10:21:39
【问题描述】:

在 Rails 中,经常会看到这样的模式(例如在 config/environments/development.rb 中):

Rails.application.configure do

  config.some_option = some_value

end

我对这个成语很感兴趣,因为我最近在研究这些配置 blocks 如何工作并最终发现 this very similar pattern,其中 configure 方法初始化配置类的(通常是记忆的)实例(具有配置选项的访问器)并将该实例对象产生给块。像这样的:

module Clearance
  class << self
    attr_accessor :configuration
  end

  def self.configure
    self.configuration ||= Configuration.new
    yield(configuration)
  end

  class Configuration
    attr_accessor :mailer_sender

    def initialize
      @mailer_sender = 'donotreply@example.com'
    end
  end
end

这就是Clearance.configure {|config| config.mailer_sender = 'something'} 起作用的原因,因为它将配置类的实例产生给块变量config

但是 Rails 这样做的方式是,没有将变量传递给该块。没有Rails.application.configure do |config|,因此该块可以更改配置对象访问器。我以为config 在该块内是未定义的,但事实并非如此。

尝试查看 rails 源代码,我怀疑它与 configurable module 有关,但我无法 100% 理解我在那里找到的代码。

【问题讨论】:

  • 我正在标记这个 Ruby,它似乎与 ruby​​ 相比与框架本身有更多的关系。

标签: ruby-on-rails ruby


【解决方案1】:

实际的 Rails railtie 似乎没有使用 Configurable 模块。

https://github.com/rails/rails/blob/5ccdd0bb6d1262a670645ddf3a9e334be4545dac/railties/lib/rails/railtie.rb#L170

我并没有声称完全了解它的用法,但显然 delegate 方法 used in Railtie class

delegate :config, to: :instance

添加一个指向Rails::Application::Configuration 实例的config 属性——我们稍后通过Rails.application.config 访问该实例。

https://apidock.com/rails/Module/delegate

【讨论】:

    【解决方案2】:

    它使用instance_eval(或class_eval,其作用基本相同)在指定对象的上下文中评估块。在块内,该对象成为隐式接收者(即self)。

    例如,使用您的代码:

    module Clearance
      class << self
        attr_accessor :configuration
      end
    
      def self.configure(&block)
        self.configuration ||= Configuration.new
        configuration.instance_eval(&block)
      end
    
      class Configuration
        attr_accessor :mailer_sender
    
        def initialize
          @mailer_sender = 'donotreply@example.com'
        end
      end
    end
    
    Clearance.configure { self.mailer_sender = 'something' }
    
    Clearance.configuration.mailer_sender #=> "something"
    

    【讨论】:

    • 但是没有隐式接收者,有config作为接收者
    • @sandre89 是和否。如果你有config.some_option = some_value,那么configsome_option(或:some_option=)的接收者,但selfconfig 的接收者。
    猜你喜欢
    • 2018-07-23
    • 2010-10-01
    • 1970-01-01
    • 2012-08-15
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    相关资源
    最近更新 更多