所以我设置了一些模型,它们基于2个抽象基类(或者更确切地说它们是类)。在Datamapper为我的用例处理STI遇到了很多麻烦,这似乎是他们灯塔页面上的一个开放的bug,我决定只是做模块来定义所有属性以保持我的模型DRY。不幸的是,我遇到了一个范围问题,更糟糕的是,我必须使用2级继承。这是我的代码:
module Part
def self.included(receiver)
receiver.class_eval do
include DataMapper::Resource
property :id, Serial
#other junk
end
end
end
module HardDrive
def self.included(receiver)
receiver.class_eval do
include Part
property :kind, Enum[:magnetic, :flash]
#buncha crap here
end
end
end
class Fujitsu
include HardDrive
property :rev, String
end
我得到的错误是:
uninitialized constant HardDrive::Enum (NameError)
from /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:80:in `const_missing'
from ./app/models/hard_drive.rb:6:in `included'
from ./app/models/hard_drive.rb:4:in `class_eval'
from ./app/models/hard_drive.rb:4:in `included'
from ./app/models/hard_drives/fujitsu.rb:2:in `include'
from ./app/models/hard_drives/fujitsu.rb:2
我在这里不知所措。任何人都知道如何解决这个问题或者更好的问题,我能做到这一点更聪明吗?
答案 0 :(得分:2)
在我看来,Enum是在DataMapper模块下定义的,并且HardDrive范围无法解析它。 (想知道为什么?)
只需放入DataMapper :: Enum而不是Enum,它应该可以工作。
在更一般的讨论中,你确定你真的需要这些抽象吗?我在代码中看到的一个缺点是,您将无法在数据库中查询部件和硬盘,因为逻辑存储在ruby模块中而不是数据库中。
更新(在作者发表评论后)
一般的答案是:忘记STI。虽然ORM很好用,但最好的部分是SQL后端抽象。虽然它们给你的印象是你可以有一个持久对象模型,但抽象经常泄漏,而STI就是一个很好的例子。我不会在这里详细介绍,但您可以在线查找资源。最好的是你保持足够接近SQL建模的最佳实践,比如一对一,一对多和多对多的关系。
这是更新版本。我没有测试它,方法名称可能不对,但你会明白这个想法:
class Part
property :serial_number
has_one Manufacturer
end
class HardDisk
property :technology
property :platters
property :model
#...
is_one Part
end
class Manufacturer
property :name #Fujitsu, ...
property :website
#...
has_many HardDisk, [:trough=>Part]
end