使用模块使用Datamapper定义属性

时间:2009-12-31 09:29:42

标签: ruby datamapper

所以我设置了一些模型,它们基于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

我在这里不知所措。任何人都知道如何解决这个问题或者更好的问题,我能做到这一点更聪明吗?

1 个答案:

答案 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