0

在我的 Rails 3.2.11 应用程序中,我需要唯一性验证器来支持条件,以便忽略软删除的记录。在 GitHub 上,我发现了一个拉取请求(https://github.com/rails/rails/pull/5321),但这个功能似乎不是当前 Rails 版本的一部分。现在我为 UniquenessValidator 类创建了一个补丁,如下所示:

module UniquenessValidatorExtension
  def build_relation(klass, table, attribute, value)
    relation = super
    relation.merge!(options[:conditions]) if options[:conditions]
    relation
  end
end

ActiveRecord::Validations::UniquenessValidator.send :include, UniquenessValidatorExtension

为了加载它,我创建了一个初始化程序。问题是,我的方法永远不会被调用。我做错了什么?

这是当前 UniquenessValidator 类的链接:https ://github.com/rails/rails/blob/0d73d6e7b6dd1900f105397460b777ef6c03d3b6/activerecord/lib/active_record/validations/uniqueness.rb

4

3 回答 3

1

就是这样include工作的:

module M; end

class C
  include M
end

C.ancestors # => [C, M, Object, Kernel, BasicObject] 

因此,在您的情况下build_relation,将调用原始类中的方法。JFYI,prependRuby 2.0 中有方法:

class C1
  prepend M
end

C1.ancestors # => [M, C1, Object, Kernel, BasicObject]

所以在你的情况下,方法build_relation将从模块中调用。

好吧,现在您可以重新打开UniquenessValidator并覆盖整个build_relation方法

于 2013-01-26T11:51:17.400 回答
0

如果该方法从未被调用,这意味着您在 ActiveRecord::Base 'required' 之后包含了您的模块。尝试在之前包含它:

config.before_initialize do
  ActiveRecord::Validations::UniquenessValidator.send :include, UniquenessValidatorExtension
end
于 2013-01-26T11:42:26.027 回答
0

@nash 解释了这个问题,但由于我使用的是 Ruby 1.9.x,所以这不是解决方案。为了让它工作,我给原来的方法加上别名,然后替换它。现在我可以从覆盖中调用别名方法。

class ActiveRecord::Validations::UniquenessValidator < ActiveModel::EachValidator
  alias_method :build_relation_orig, :build_relation
  def build_relation(klass, table, attribute, value)
    relation = self.build_relation_orig(klass, table, attribute, value)
    relation = relation.and(options[:conditions]) if options[:conditions]
    relation
  end
end
于 2013-01-26T18:58:45.437 回答