【问题标题】:NoMethodError when defining custom DataMapper property type定义自定义 DataMapper 属性类型时出现 NoMethodError
【发布时间】:2013-04-09 16:21:07
【问题描述】:

我正在使用 DataMapper 1.2.0 并尝试定义自定义属性类型以保存在数据库中。我试图了解我应该如何做到这一点,但我不断收到NoMethodError

对象是Dog,但是这个类型来自我无法控制的gem,所以我不能让它继承自DataMapper::Property::Object,所以我想我需要创建一个新类型,它将是自定义属性(DatabaseDog)。我对the documentation的理解是它需要两种方法:

  • #load(value) 从数据库中获取一个字符串并返回它所代表的Dog
  • #dump(value) 接受 Dog 并返回一个字符串,该字符串将持久保存在数据库中

我不断收到错误的事实让我觉得我误解了这一点。

我应该如何正确创建这个自定义类型?

编辑:我稍微改变了转储方法,发现它一直在接收一个字符串。为什么#dump 接收字符串作为参数?它不应该接收我分配的Dog 对象吗?

test.rb

# The setup

require 'dm-core'
require 'dm-migrations'
require 'dm-sqlite-adapter'

class Dog
  attr_accessor :name
end

class DatabaseDog < DataMapper::Property::Text
  def load(value)
    d = Dog.new
    d.name = value
    d
  end

  def dump(value)
    puts "got here: #{value.inspect}"
    if value.nil?
      value
    else
      value.name
    end
  end
end

class User
  include DataMapper::Resource
  property :id, Serial, key: true
  property :pet, DatabaseDog
end

DataMapper.setup(:default, "sqlite3://#{File.join(Dir.pwd, "users.db")}")
DataMapper.finalize
DataMapper.auto_upgrade!


# Finally, the test

ein = Dog.new
ein.name = "Ein"

spike = User.create
spike.pet = ein

spike.save #=> NoMethodError

错误

got here: nil
got here: "#<Dog:0x007fca399b7d40>"
./test.rb:19:in `dump': undefined method `name' for "#<Dog:0x007fba19960c00>":String (NoMethodError)
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/property.rb:700:in `valid?'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource/persistence_state/dirty.rb:88:in `block in valid_attributes?'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource/persistence_state/dirty.rb:87:in `each_key'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource/persistence_state/dirty.rb:87:in `valid_attributes?'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource/persistence_state/dirty.rb:21:in `commit'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource.rb:956:in `_persist'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource.rb:987:in `block in update_with_hooks'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource.rb:984:in `catch'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource.rb:984:in `update_with_hooks'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource.rb:1021:in `save_self'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource.rb:1006:in `block in _save'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource.rb:1222:in `run_once'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource.rb:1005:in `_save'
        from (...)/test/.bundle/gems/dm-core-1.2.0/lib/dm-core/resource.rb:405:in `save'
        from ./test.rb:42:in `<main>'

【问题讨论】:

    标签: ruby datamapper ruby-datamapper


    【解决方案1】:

    根据文档,DatabaseDog 应该继承自 DataMapper::Property::Object 而不是 DataMapper::Property::Text。

    【讨论】:

    • 这并不能解决问题,并且文档说“要将基元分配给类型,要么使类型从 DataMapper::Property::(PrimitiveClass) 下降,要么在类定义中使用 primitive PrimitiveClass。”
    • 但它不是原始类型,它是 Dog 对象。文档说“所有类型都是应该从 DataMapper::Property::Object 继承的类”。如果您的加载和转储方法返回字符串,那么您可以从 DataMapper::Property::String 继承。
    • 它有效,但现在我又感到困惑了。如果我从DM::Property::Object 继承,我会在数据库中得到一个文本字段,并从DM::Property::DateTime..Integer 继承给我数据库中的时间戳或整数,但如果我从DM::Property::String 继承,我会收到错误消息。为什么会有差异?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多