覆盖 ActiveRecord 属性方法

Posted

技术标签:

【中文标题】覆盖 ActiveRecord 属性方法【英文标题】:Override ActiveRecord attribute methods 【发布时间】:2010-09-27 06:53:56 【问题描述】:

我所说的一个例子:

class Person < ActiveRecord::Base
  def name=(name)
    super(name.capitalize)
  end
  def name
    super().downcase  # not sure why you'd do this; this is just an example
  end
end

这似乎可行,但我刚刚阅读了ActiveRecord::Base docs 中关于覆盖属性方法的部分,它建议使用read_attributewrite_attribute 方法。我认为我在上面的示例中所做的事情一定有问题;否则,他们为什么会祝福这些方法是覆盖属性方法的“正确方法”?他们还强迫一个更丑陋的成语,所以一定有充分的理由......

我真正的问题:这个例子有什么问题吗?

【问题讨论】:

【参考方案1】:

http://errtheblog.com/posts/18-accessor-missing 提供有关此主题的一些重要信息。

总而言之,ActiveRecord 确实正确处理了对 ActiveRecord 属性访问器的超级调用。

【讨论】:

【参考方案2】:

我有一个 Rails 插件,它可以像你期望的那样让属性覆盖与 super 一起工作。你可以在github找到它。

安装:

./script/plugin install git://github.com/chriseppstein/has_overrides.git

使用方法:

class Post < ActiveRecord::Base

  has_overrides

  module Overrides
    # put your getter and setter overrides in this module.
    def title=(t)
      super(t.titleize)
    end
  end
end

一旦你完成了这些事情就可以工作了:

$ ./script/console 
Loading development environment (Rails 2.3.2)
>> post = Post.new(:title => "a simple title")
=> #<Post id: nil, title: "A Simple Title", body: nil, created_at: nil, updated_at: nil>
>> post.title = "another simple title"
=> "another simple title"
>> post.title
=> "Another Simple Title"
>> post.update_attributes(:title => "updated title")
=> true
>> post.title
=> "Updated Title"
>> post.update_attribute(:title, "singly updated title")
=> true
>> post.title
=> "Singly Updated Title"

【讨论】:

【参考方案3】:

作为 Aaron Longwell 回答的扩展,您还可以使用“哈希表示法”来访问具有覆盖访问器和修改器的属性:

def name=(name)
  self[:name] = name.capitalize
end

def name
  self[:name].downcase
end

【讨论】:

哈希表示法可能有效,但 self.attribute 在 3.2.16 上破坏了堆栈。 这样的好处是支持||=进行默认:def name; self[:name] ||= 'anon'; end 对我来说,这种哈希表示法有效。但我不知道它起作用的原因。谁能解释一下?【参考方案4】:

与 Gareth 的 cmets 相呼应...您的代码将无法按所写的那样工作。应该这样改写:

def name=(name)
  write_attribute(:name, name.capitalize)
end

def name
  read_attribute(:name).downcase  # No test for nil?
end

【讨论】:

正是我需要的。谢谢亚伦。 这不再是真的。要么超级,要么现在有效。不过,我还没有测试过哈希表示法。 在rails 3中,Aaron在此处指定的阅读器方法有效,但原始海报指定的作者(将名称提供给super)工作正常,恕我直言,比手动将属性写入Aaron更干净建议。 我已经测试了下面 mipadi 给出的哈希方法,它就像一个魅力(Rails v 3.2.6) 这已在 Rails 6.1 中删除:github.com/rails/rails/commit/…

以上是关于覆盖 ActiveRecord 属性方法的主要内容,如果未能解决你的问题,请参考以下文章

覆盖ActiveRecord子类中的'=='方法有意义吗?

覆盖默认访问器时更新属性的问题

如何在具有名为“属性”的列的数据库上使用 ActiveRecord? (危险属性错误)

Rails 4 - 从已过滤的 Active Record 查询中删除属性

验证外部gem的ActiveRecord模型的最佳方法

使用 active admin、polyamorous、activerecord 更新 squeel