嗯,问题如下。我的模型层次结构如下:
class A < ActiveRecord::Base
end
Class B < A
end
class C1 < B
end
class C2 < B
end
在其中一个控制器中,我需要搜索B,C1或C2。 如果加载相关模型,Rails会执行此操作。 所以sql查询应该(并且理想情况下)包含类似
的内容B.find 224
# => SELECT "bs".* FROM "bs" WHERE "bs"."type" IN ('B','C1','C2') AND "bs"."id" = 224 LIMIT 1
那就是需要什么。但是,事实证明,模型在每个请求上都被卸载而不会再次加载(不确定原因)。 在这种情况下,如果模型不在内存中,ActiveRecord将进行类似
的查询B.find 224
# => SELECT "bs".* FROM "bs" WHERE "bs"."type" IN ('B') AND "bs"."id" = 224 LIMIT 1
如果您只是在调用C1或C2之前发现它们的类型将包含在sql中
C1
B.find 224
# => SELECT "bs".* FROM "bs" WHERE "bs"."type" IN ('B','C1') AND "bs"."id" = 224 LIMIT 1
我尝试在初始化程序中加载这些模型。 eval C1,需要'app / models / c1.rb',require_dependancy'app / models / c1.rb',但这些都不起作用。实际上,他们都工作了一次。服务器启动后只有一次。我怀疑在生产环境下不存在这样的问题,但它非常烦人。
一个丑陋的解决方案是在B定义之后调用C1和C2,在这种情况下它按预期工作,但是,正如我已经说过的那样,它很丑陋
class B < A
end
C1, C2
有更好的想法吗?
更新已移至回答。
答案 0 :(得分:0)
您能解释一下这个数据结构想要实现的目标吗?我看到在模型继承中设置了单表继承模式,但是我无法看到你想要实现的初始解决方案。
答案 1 :(得分:0)
如果要在开发中关闭类重新加载,可以这样做。在config / environments / development.rb中,只需make:
config.cache_classes = true
而不是默认的false。这将关闭所有类的开发模式类重载,这有点不方便。从理论上讲,这应该是一种只从开发模式类重新加载中豁免特定类的方法,但它不断从rails版本转换为rails版本,并且通常不能正常工作,而且我没有跟踪如何做它在当前的轨道中或是否有效。我不喜欢你自己通过猴子补丁实现这个功能的hacky尝试 - 事实上Rails过去曾试图以各种方式支持这种功能,但失败表明它很难做到,你可能还没有'吨。
但是。我认为这不是你真正想要的。我认为你的整体设计有些麻烦,关闭课程重新加载只是一种解决方法。但我不确定你到底要做什么或者发生了什么。 ActiveRecord确实支持“单表继承”模型类hieararchy - 但似乎你试图做“多表继承”而不是。
如果AR支持多表继承,我自己不确定 - 我会寻找相关的文档,如果AR支持它,那就按照它告诉你的方式去做 - - 如果AR不支持它,请放弃设计,除非你真的想要进入AR的内部并找出如何让AR这样做或者写一个扩展到AR来做。它几乎可以工作的事实可能会让我猜测AR支持多表继承,但是你缺少某种配置来告诉它。
还有Rails“多态关联”功能,可能对您有用,也可能没用。
基本上,抱歉不确定AR是否可以做你想要的,但如果我是你,我只会尝试它,如果我能找到AR实际上支持它的证据 - 即使你看起来通过关闭工作dev-mode类重新加载,如果你正在尝试做一些AR不支持的东西,可能还有其他奇怪的bug等着你。 AR是复杂的代码。
答案 2 :(得分:0)
好的,我想我找到了某种解决方案。这不是很令人印象深刻,但似乎有效:
我需要在ActiveSupport :: Dependencies中添加一个hack。
所以这是黑客名单:
#lib/system_hacks/active_support.rb
module ActiveSupport #:nodoc:
module Dependencies #:nodoc:
#this array contains all the constants that have to be constantly loaded
mattr_accessor :constantly_loaded_files
self.constantly_loaded_files = []
#redefining the method, with additional line
def remove_unloadable_constants!
autoloaded_constants.each { |const| remove_constant const }
autoloaded_constants.clear
Reference.clear!
explicitly_unloadable_constants.each { |const| remove_constant const }
#a hack
constantly_loaded
end
#will simply make a call for each constants
#in that case they will be updated... but still in the memory
def constantly_loaded
constantly_loaded_files.each do |file|
file.to_s.classify.constantize
end
end
end
end
在初始化器中有一个小文件来加载hack并分配一个常量数组:
#config/initializers/model_loader.rb
require File.join(Rails.root, 'lib','system_hacks','active_support')
module ActiveSupport #:nodoc:
module Dependencies #:nodoc:
self.constantly_loaded_files = [A, B, C1, C2]
end
end
如果您有任何意见,我很乐意听取他们的意见。