【问题标题】:How can I overwrite a getter method in an ActiveRecord model?如何覆盖 ActiveRecord 模型中的 getter 方法?
【发布时间】:2014-03-17 02:31:39
【问题描述】:

我正在尝试覆盖 ActiveRecord 模型的 getter 方法。我在模型Category 中有一个名为name 的属性,我希望能够做这样的事情:

def name
  name_trans || name
end

如果name_trans 属性不为零,则返回它,否则返回name 属性。我该怎么做?

这应该像这样正常调用:

@category.name

【问题讨论】:

    标签: ruby-on-rails ruby rails-activerecord getter-setter


    【解决方案1】:

    Rails Style Guide 建议使用 self[:attr] 而不是 read_attribute(:attr)

    你可以这样使用它:

    def name
      name_trans || self[:name]
    end
    

    【讨论】:

    【解决方案2】:

    更新:根据Rails Style Guide 的首选方法是使用self[:name] 而不是read_attributewrite_attribute。我鼓励你跳过我的回答,而是更喜欢this one


    您完全可以这样做,只是您需要使用read_attribute 来实际获取name 属性的值并避免递归调用name 方法:

    def name 
      name_trans || read_attribute(:name)
    end
    

    【讨论】:

    • 知道为什么 Rubocop 更喜欢 self[:name] 而不是 read_attribute[:name] 吗?
    【解决方案3】:

    我想添加一个覆盖getter方法的选项,简单来说就是:super。

    def name
      name_trans || super
    end
    

    这不仅适用于属性 getter 方法,也适用于关联 getter 方法。

    【讨论】:

    【解决方案4】:

    覆盖 getter 并使用 read_attribute 不适用于关联,但您可以改用 alias_method_chain

    def name_with_override
      name_trans || name_without_override
    end
    
    alias_method_chain :name, :override
    

    【讨论】:

    • 你能举个合适的例子吗...?
    • 好吧。我刚看到doco。现在,如果我在模型对象上调用name,哪个将被称为-name_with_overridename_without_override
    • name 现在将调用name_with_override。如果出于某种原因想调用原始方法,可以调用name_without_override
    • 哦,我明白了.. 感谢您的回复//
    • 此答案在 rails 5 中已弃用:Deprecate alias_method_chain in favour of Module#prepend
    【解决方案5】:

    如果你使用这样的商店属性

    store :settings, accessors: [:volume_adjustment] 
    

    或 使用宝石 hstore_accessorgem link

    所以你最终在模型上使用了store 方法,然后要覆盖那些你不能使用self.read_attribute 的方法,你必须像这样使用super

    def partner_percentage
      super.to_i || 10
    end
    

    【讨论】:

      【解决方案6】:

      你可以使用 Rails 的 read_attribute 方法。 Rails docs

      【讨论】:

      • 虽然此链接可能会回答问题,但 SO 上不允许仅链接答案,请从该链接后面的内容中为您的答案添加一些上下文。谢谢! :)
      【解决方案7】:

      如果有人想在getter方法中更新name_trans之后的值,你可以使用self[:name]=。

      def name
        self[:name] = name_trans || self[:name]
        # don't do this, it will cause endless loop
        # update(name: name_trans)
      end
      

      【讨论】:

        猜你喜欢
        • 2015-07-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-01
        • 1970-01-01
        • 2010-09-27
        • 1970-01-01
        • 2012-10-14
        相关资源
        最近更新 更多