【问题标题】:Ruby method still defined after Module/Class is reloaded重新加载模块/类后仍定义 Ruby 方法
【发布时间】:2015-04-10 09:56:55
【问题描述】:

我在为我的 Rails 应用程序构建 ruby​​ gem 时遇到了类重新加载问题。

背景

在 gem 中,我定义了以下类

module MyGem
  class AppConfigBase

    def app_title
      "Title Missing"
    end

  end
end

在 Rails 应用程序中,我创建了一个 config/my_gem.rb 文件来保存一些特定于应用程序的覆盖。 (我的目标是让 gem 的用户定义一些信息,但在超类中提供一些默认值。)

module MyGem
  class AppConfig < AppConfigBase

    def app_title
      "Great App"
    end

  end
end

在 gem 内部的某个时刻,我调用 MyGem::AppConfig.new.app_title 并收到正确的字符串。耶!

接下来,我决定稍微挑战一下:我想让自动加载工作,这样开发人员就不必在每次更改此文件时都重新启动 rails 服务器。

我首先尝试查看 Rails 是否已经设置为执行此操作。我从AppConfig 类中删除了app_title 方法。当我重新加载页面时,我仍然得到返回的“Great App”字符串。 :( Rails 没有重新加载config/my_gem.rb(或配置目录中的任何内容),所以这是预期的结果。

接下来,我尝试添加以下初始化程序:

if Rails.env.development?
  ActionDispatch::Callbacks.after do
    load "#{Rails.root}/config/my_gem.rb"
  end
end

上述初始化程序部分解决了问题,但我想了解为什么它不能完全解决问题。有了这个初始化器,

  1. 如果我从子类中删除 app_title 方法,我仍然会得到错误的字符串(子类方法中的那个...不应该再存在了)。
  2. 如果我重新启动服务器,我会得到预期的字符串的超类版本。
  3. 现在,如果在子类中重新添加方法并调用 app_title,我会得到字符串的子类版本!

所以当我添加一个方法时,初始化程序中的加载调用似乎会拾取新方法。但是,如果我删除一个方法,它似乎没有帮助。

  1. 为什么会这样?
  2. 如何使该文件在更改时自动重新加载? (我看到的最简单的解决方法是将 my_gem.rb 移动到 config/my_gem/my_gem.rb,然后将 config/my_gem 添加到 Rails 中的自动加载路径中,但我不想创建这个额外的目录只是为了自动加载一些东西。)

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4


    【解决方案1】:

    这不是自动加载的工作原理。 Rails 的重新加载器(与自动加载器机制不同,但依赖于自动加载器机制)通过取消定义常量来工作,然后通过要求定义它们的文件来重新创建它们。你真正想要的是标记常量unloadable。在您的覆盖中:

    module MyGem
      class AppConfig < AppConfigBase
        unloadable
    
        def app_title
          "Great App"
        end
      end
    end
    

    这会将常量添加到每个请求要卸载的常量列表中,但它希望它可以通过加载 my_gem/app_config.rb 来加载常量并期望它出现在你的加载路径。出于这个原因,这种覆盖通常发生在lib/ 而不是config/,因为前者在您的加载路径中,而后者不在。它意味着除了使用它的请求之外,任何请求都可能不需要该常量。

    按照惯例,更改 config 中的文件需要重新启动才能应用。

    【讨论】:

    • 感谢您的解释和提示。
    猜你喜欢
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-30
    • 2016-01-24
    • 1970-01-01
    相关资源
    最近更新 更多