Rails单表继承与动态定义的类

时间:2016-12-24 11:24:15

标签: ruby-on-rails ruby

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

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

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

如果你尝试使用'类型'来设置新的Poi对象,则Rails会引发错误。与Poi的子类不匹配的属性(所以子类必须先前定义),我们提出了以下解决方案,用于基于class_name动态创建Poi子类:

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

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

  3. 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文件来定义它们),但是检查{ {1}}首先(因为require_dependency定义的那些不需要重新定义)。
    2. 即便是所有这些复杂性使得我们在开始时使用STI几乎感到后悔,它仍然正常 - 在开发中

      但是在生产环境中,在创建提供if Object.const_defined? category.class_name的新类别之后,类没有被定义,因为当尝试使用该子类创建新的Poi时正在引发错误class_name

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

1 个答案:

答案 0 :(得分:0)

  

10.5 require_dependency和Initializers

     

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

     

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

来自http://guides.rubyonrails.org/autoloading_and_reloading_constants.html。从我在此处阅读的内容来看,children中的require_dependency似乎在不同环境之间有所不同。我发现了一个类似的问题here - 看看是否有帮助。

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