5

我正在使用 ActiveAttr,它通过块选项为您提供了很好的初始化:

person = Person.new() do |p|
  p.first_name = 'test'
  p.last_name = 'man'
end

但是,在包含 ActiveAttr::Model 的特定类中,我想绕过此功能,因为我想将该块用于其他用途。所以我们开始:

class Imperator::Command
 include ActiveAttr::Model
end


class MyCommand < Imperator::Command

  def initialize(*args, &block)
    @my_block = block

    super(*args)
  end
end

这惨遭失败,因为块仍然被传递到链上,最终在 ActiveAttr 内部,这段代码被运行:

def initialize(*)
  super
  yield self if block_given?
end

所以如果我的电话看起来像这样:

MyCommand.new() { |date| date.advance(month: 1) }

它失败如下:

NoMethodError: undefined method `advance' for #<MyCommand:0x007fe432c4fb80>

由于 MyCommand 没有方法 :advance 它,因此对 MyCommand 的调用显然失败了。

所以我的问题是,有没有一种方法可以在我super再次调用之前从方法签名中删除该块,以便该块不会比我重写的初始化程序更远?

4

2 回答 2

12

尝试

super(*args,&nil)

& 使 ruby​​ 使用 nil 作为块,而 ruby​​ 似乎足够聪明,可以意识到这意味着没有块。

于 2012-05-10T20:07:43.457 回答
0

这当然是一个巧妙的技巧,但更好的方法是不直接使用 ActiveAttr::Model 模块,而只包含您需要的模块。

而不是

class Imperator::Command
  include ActiveAttr::Model
end

class Imperator::Command
  include BasicModel
  # include BlockInitialization
  include Logger
  include MassAssignmentSecurity
  include AttributeDefaults
  include QueryAttributes
  include TypecastedAttributes

  def initialize(*args, &block)
    @my_block = block
    super(*args)
  end
end

一旦你看到 ActiveAttr::Model 正在做的分解图,可能还有其他你不想要的东西。在这种情况下,只需简单地省略包含。其目的是为模型构建提供一个点菜的方法。

于 2012-05-28T20:01:17.373 回答