为Mongoid哈希字段设置默认哈希键

3

我有一个带有哈希字段的 Mongoid 模型。这个 Mongoid 模型使用单一集合继承来创建子类。现在我想为主模型的每个子类设置不同的默认哈希键。

主模型如下:

 class Sport
   include Mongoid::Document
   field :rules, type: Hash, default: {}
 end

我想设置不同的默认哈希键用于:rule哈希字段的子类。例如,对于足球,我想要规则:{:越位 =>'',:罚款 =>''}。对于拳击,我们可能有规则:{:咬人=>'不允许'}的哈希键。开源应用程序Errbit使用子类中的常量设置默认哈希键,但我可以看到它们如何使用该常量来填充哈希:https://github.com/errbit/errbit/blob/master/app/models/issue_trackers/github_issues_tracker.rb

 class Sport::Football < Sport
 end

 class Sport::Boxing < Sport
 end

我在子类中覆盖了字段定义,如下所示,在rails控制台中可以正常工作。当我执行a = Sport::Football.new然后调用a.smtp时,返回默认设置。但问题在于,当我转到父类并执行b = Sport.newb.smtp时,我希望它能够列出子类的所有默认键,但实际上却不能,因为我在子类中重写了哈希字段

 class Sport::Football < Sport
    field :rules, type: Hash, default: {:offside => '', :penalty => ''}
 end

有没有一种方法可以在不覆盖字段定义的情况下为子类设置默认哈希键。可以通过在每个子类中覆盖哈希字段的setter和getter来实现这一点。

1个回答

5
< p > :default 选项可以将 lambda 作为其值。在该 lambda 中, self 将是您要创建的新实例。这意味着您可以(间接地)调用方法来提供默认值:

class Sport
  include Mongoid::Document
  field :rules, type: Hash, default: lambda { default_rules }
end

class Sport::Football < Sport
private
  def default_rules
    { :offside => '', :penalty => '' }
  end
end

class Sport::Boxing < Sport
private
  def default_rules
    { :biting => 'not allowed except for ears' }
  end
end

当然,您不一定需要将default_rules设置为私有的。如果您想直接实例化Sport,则还需要在其中包含default_rules

您也可以使用其中一个回调函数手动设置规则:

class Sport
  include Mongoid::Document
  field :rules, type: Hash
  after_initialize :set_default_rules, :if => :new_record? # Or one of the other callbacks.
end

子类可以在其 set_default_rules 实现中编写 self.rules = ...


谢谢。我需要添加的唯一更改是在运动模型中表示 default_rules 的空方法。如果没有它,如果我调用 Sport.new,它会抛出错误 **NameError: undefined local variable or method `default_rules'**。如果没有更好的方法来防止该错误,我可以将其保留在那里。 - brg
那是有意为之的,我把Sport看作是一种虚拟基类,它本身永远不会被实例化(即只有子类会被实例化)。 - mu is too short
我本来希望通常的 :default => :method_name 风格可以工作,但是没有成功(至少在 Mongoid3 中如此,在 Mongoid4 中可能值得一试),因此使用了 lambda 间接引用。 - mu is too short

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接