重新加载Module / Class后仍然定义Ruby方法

时间:2015-03-27 19:23:39

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

在为我的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是否已经设置好了。我从app_title课程中删除了AppConfig方法。当我重新加载页面时,我仍然返回“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,我会得到该字符串的子类版本!
  4. 因此,当我添加方法时,初始化程序中的加载调用似乎会拾取新方法。但是,如果我删除一个方法,它似乎没有帮助。

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

1 个答案:

答案 0 :(得分:1)

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

module MyGem
  class AppConfig < AppConfigBase
    unloadable

    def app_title
      "Great App"
    end
  end
end

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

通常情况下,更改config中的文件需要重新启动才能应用。