ruby-on-rails - 具有动态定义类的 Rails 单表继承

标签 ruby-on-rails ruby

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

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

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

如果您尝试实例化一个新的 Poi 对象时,Rails 会抛出一个错误,该对象的“类型”属性与 Poi 的子类不匹配(因此必须预先定义子类),因此我们提出了以下动态解决方案基于 class_name 创建 Poi 子类:

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

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

Category.all.each 做 |category|

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

结束

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

尽管所有这些复杂性都让我们几乎后悔一开始就使用 STI,但它运行良好 - 在开发中

但在生产环境中,在创建一个提供class_name的新类别后,类没有被定义,因为当试图用它创建一个新的Poi时子类引发错误 uninitialized constant

我在生产环境的 Rails 控制台中确认 after_create 钩子(Hook)正在工作,因为类是在那里定义的。我的大胆猜测是,因为我们使用 Unicorn,这个错误可能与应用程序代码的 fork 有关,但我不知道如何继续。

最佳答案

10.5 require_dependency and Initializers

One could think about doing some require_dependency calls in an initializer to make sure certain constants are loaded upfront, for example as an attempt to address the gotcha with STIs.

Problem is, in development mode autoloaded constants are wiped if there is any relevant change in the file system. If that happens then we are in the very same situation the initializer wanted to avoid!

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

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

关于ruby-on-rails - 具有动态定义类的 Rails 单表继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41312813/

相关文章:

ruby - 如何在我的 .zshrc 中包含一个文件?

ruby-on-rails - 我如何在 Ruby on Rails 中创建联系我们表单?

ruby-on-rails - Twitter Bootstrap & rails - 内容居中并固定最小宽度

ruby-on-rails - 是否可以使用载波仅重新创建特定版本?

mysql - Rails 中用于消息传递系统的 Tricky MySQL 查询 - 请帮助

ruby-on-rails - 如何在 Windows xp 中的 xampp 中部署 ruby​​ on rails 应用程序?

ruby - 如何在 Windows 上设置 RUBYOPT 以使用附加包含

ruby-on-rails - Rails 应用程序错误 : Premature end of script headers

ruby-on-rails - 在 windows xp(32 位)上的 Ruby on Rails 上安装 Typhoeus

ruby-on-rails - 寻求构建电子商务 Rails 应用程序的指导