2

所以我正在建立一些模型,它们基于 2 个抽象基类(或者更确切地说它们曾经是类)。在 Datamapper 为我的用例处理 STI 遇到了很多麻烦之后,这似乎是他们灯塔页面上的一个开放错误,我决定改为使用模块来定义所有属性以保持我的模型干燥。不幸的是,我遇到了范围界定问题,更糟糕的是,我必须使用 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

我在这里不知所措。任何人都知道我可以如何解决这个问题,或者更好,我可以用更聪明的方式来解决这个问题吗?

4

1 回答 1

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
于 2009-12-31T22:11:05.787 回答