覆盖 ActiveRecord 的追加方法 (<<) 属性

Override append method (<<) of an ActiveRecord property

我有一个 ActiveRecord class,它的 属性 是一个数组(Postgres 数组列),我希望数组中的项目是唯一的。覆盖数组本身发生的方法的最佳方法是什么,例如 #<< ?

module PgTags

  def tags=(value)
    write_attribute :tags, value.uniq
  end

end

class Rule < ActiveRecord::Base
  include PgTags
end

r = Rule.new
r.tags = %w(one two one)
puts r.tags # outputs ['one', 'two']
r.tags << 'one'
puts r.tags # should still output ['one', 'two']

r.tags << value的时候也可以这样看r.tags.<<(value)tags 方法将 return Array 的一个实例,然后会发生以下情况: array.<<(value) 数组将接收 << 方法,而不是 tags 属性。

您必须覆盖 Array 上的 << 方法。

最好退回到 r 对象并向 Rule 添加一个 add_tags 方法来实现您提出的逻辑。您要求的是可能的,但比这更复杂:

module PgTags
  def tags=(value)
    write_attribute :tags, value.uniq
  end

  def add_tags(*t)
    self.tags = (tags << t).flatten.uniq 
  end
end

class Rule < ActiveRecord::Base
  include PgTags
end

r = Rule.new
r.tags = %w(one two one)
puts r.tags #=> ['one', 'two']
r.tags.add_tags 'one'
r.tags.add_tags 'three'
puts r.tags #=> ['one', 'two', 'three']

add_tags 方法的行为与您在使用 << 时预期的一样,只是它处理 uniq 逻辑并将新值分配给规则自己的 tags 属性。

另一种方法(现在我看到这是 Postgres)会这样:

class Rule < ActiveRecord::Base
  before_validation :ensure_tags_unique

  private
  def ensure_tags_unique
    self.tags = self.tags.uniq
  end
end

这保留了 AR 内置的 <<= 功能。