【问题标题】:Rails Single Table Inheritance with dynamically defined classesRails 单表继承与动态定义的类
【发布时间】:2016-12-24 11:24:14
【问题描述】:

在使用 Rails STI(单表继承)时,我定义了一个名为 Poi(兴趣点)的模型。

我们的应用程序要求 Poi 的子类(如餐厅、俱乐部等)必须在 Admin::Categories 视图中创建(其中有一个class_name 字符串输入字段),以便管理员应该能够随时创建一个新的子类,而不需要程序员打开一个带有空(无用)子类的新 ruby​​ 文件并重新部署应用程序。

同时,如果将来我们想为 Poi 的子类指定不同的行为(实例/类方法),我们可以只创建该 ruby​​ 文件,但这应该是一个选项而不是强制性的。对于该子类具有不同字段的不同表单也是如此:我们只需要在该子类中设置一个partial_name_for_form 实例方法,该方法返回一个带有部分名称的字符串,并且视图将相应地呈现它。如果没有找到,则呈现默认的 Poi 视图。

如果您尝试实例化具有与 Poi 的子类不匹配的 'type' 属性的新 Poi 对象(因此必须事先定义子类),Rails 会引发错误,因此我们提出了以下动态解决方案根据 class_name 创建 Poi 子类:

  1. 模型类别中的 after_create 钩子立即使用以下代码定义新类:Object.const_set(category.class_name, Class.new(Poi))

  2. 模型 Poi 文件中的 require_dependency 调用(因为它在自动加载路径中)要求我们最终创建硬编码子类的子类的 ruby​​ 文件(仅当文件存在时):

Category.all.each do |category|

require_dependency category.class_name.underscore if File.exist (File.join("app","models","pois","#{category.class_name.underscore}.rb"))

end

  1. 使用#1 中相同的代码定义所有剩余类的初始化程序(“剩余”是指其他没有自己定义它们的 ruby​​ 文件的子类),但首先检查if Object.const_defined? category.class_name(因为那些由 require_dependency 定义的不需要重新定义)。

即使是所有这些复杂性都让我们几乎后悔当初使用 STI,它运行良好 - 在开发中

但在生产环境中,在创建提供class_name 的新类别后,没有定义该类,因为尝试使用该子类创建新 Poi 时会引发错误uninitialized constant

我在生产环境的 Rails 控制台中确认 after_create 钩子正在工作,因为在那里定义了类。我的猜测是因为我们使用了 Unicorn,所以这个 bug 可能与应用程序代码的分叉有关,但我不知道如何进行。

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    10.5 require_dependency 和初始化程序

    可以考虑在初始化程序中进行一些 require_dependency 调用,以确保预先加载某些常量,例如尝试使用 STI 解决问题。

    问题是,在开发模式下,如果文件系统有任何相关更改,自动加载的常量会被擦除。如果发生这种情况,那么我们将处于初始化程序想要避免的相同情况!

    来自http://guides.rubyonrails.org/autoloading_and_reloading_constants.html。从我在这里读到的内容来看,initializer 中的require_dependency 似乎在不同环境之间的工作方式不同。我发现了一个类似的问题here - 看看是否有帮助。

    由于模型损坏,我会避免创建动态常量。

    【讨论】:

    • emaillenin,感谢您的回复,但我已经在 Rails 指南中阅读过,也看到了之前的 SO 问题。据我了解,Rails 指南很清楚不要在 initializer 中使用require_dependency;在您链接到 Rails 指南的同一主题中,您会看到它以短语 Calls to require_dependency have to be strategically written in autoloaded spots. 结尾。这就是为什么我在第 2 项中声明我在模型中使用require_dependency,这是一个自动加载的点。
    • 另外,您能否详细说明为什么我们拥有的是“损坏的模型”?我们正在尝试使用单表继承来遵循 Rails 指南。
    • Single Table Inheritance 很好,但动态创建实体/模型不是。它导致了您在帖子中已经提到的问题。您正在更改 Rails 初始化应用程序的方式。因此,当您升级 Rails 本身时,它不是面向未来的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-21
    • 2019-01-02
    • 1970-01-01
    相关资源
    最近更新 更多