Ruby on rails Monkey patch Rails UniquenessValidator支持条件

Ruby on rails Monkey patch Rails UniquenessValidator支持条件,ruby-on-rails,ruby,validation,monkeypatching,Ruby On Rails,Ruby,Validation,Monkeypatching,在我的Rails 3.2.11应用程序中,我需要唯一性验证器来支持条件,以便忽略软删除记录。在GitHub上,我发现有一个拉请求正在这样做(https://github.com/rails/rails/pull/5321)但是这个特性似乎不是当前Rails版本的一部分。现在我为UniquenessValidator类创建了一个补丁,如下所示: module UniquenessValidatorExtension def build_relation(klass, table, attrib

在我的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类的链接:

如果从未调用该方法,则意味着您已在ActiveRecord::Base“必需”之后包含模块。在以下情况之前尝试将其包括在内:

config.before_initialize do
  ActiveRecord::Validations::UniquenessValidator.send :include, UniquenessValidatorExtension
end

这就是
include
的工作原理:

module M; end

class C
  include M
end

C.ancestors # => [C, M, Object, Kernel, BasicObject] 
因此,在您的示例中,将调用来自原始类的方法
build\u relation
。JFYI,Ruby 2.0中有
prepend
方法:

class C1
  prepend M
end

C1.ancestors # => [M, C1, Object, Kernel, BasicObject]
因此,在您的案例中,将从模块中调用方法
build\u relation


好的,现在您可以重新打开
uniquenessvalidater
并覆盖整个
build\u relationship

这个问题是由@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
class ActiveRecord::Validations::UniquencesValidator
这正是问题所在。但是由于我使用Ruby 1.9.x,
prepend
对我来说不是一个解决方案。我找到了另一种方法,我会在这篇文章的另一个答案中解释这一点。谢谢