【问题标题】:setting default hash keys for mongoid hash field为 mongoid 散列字段设置默认散列键
【发布时间】:2014-04-01 10:49:57
【问题描述】:

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

主要型号

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

我想为 :rule 散列字段 设置不同 默认散列键 的子类。例如,对于足球,我想要 rules:{:offside => '', :penalty => ''} 对于拳击,我们可能有 rules 的哈希键:{:biting = > '不允许'}。开源应用程序 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 来做到这一点。

【问题讨论】:

    标签: ruby-on-rails mongodb ruby-on-rails-4 mongoid mongoid4


    【解决方案1】:

    :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,您还需要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'。如果没有更好的方法来防止该错误,我可以将其留在那里。
    • 那是故意的,我认为 Sport 是一种虚拟基类,它本身永远不会被实例化(即只有子类会被实例化)。
    • 我实际上希望通常的:default =&gt; :method_name 风格可以工作,但没有乐趣(至少在 Mongoid3 中,可能值得在 Mongoid4 中尝试),因此使用 lambda 间接。
    猜你喜欢
    • 2021-08-09
    • 2015-09-12
    • 1970-01-01
    • 1970-01-01
    • 2016-09-04
    • 2014-09-05
    • 1970-01-01
    • 2013-05-16
    • 2011-12-25
    相关资源
    最近更新 更多