如何以编程方式将ActiveModel验证器从一个模型复制到另一个模型?

时间:2014-04-26 12:26:59

标签: ruby-on-rails ruby validation

我正在编写一个库,需要以编程方式将验证从一个模型复制到另一个模型,但我很难知道如何解决这个问题。

我有一个ActiveModel::Model的模型,有一些验证:

class User < ActiveRecord::Base
  validates :name, presence: true
end

另一个我希望获得相同验证的模型:

class UserForm
  include ActiveModel::Model
  attr_accessor :name
end

现在,我希望UserForm提供与User相同的验证,而无需修改User。复制验证器不起作用,因为ActiveModel::Validations在验证检查期间挂钩回调:

UserForm._validators = User._validators
UserForm.new.valid?
# => true             # We wanted to see `false` here, but no validations
                      # are actually running because the :validate callback
                      # is empty.

不幸的是,似乎并不是一种简单的方法,我可以通过编程方式为一个模型提供另一个验证回调并且仍然有效。我认为我最好的选择是,如果我可以让Rails根据给定时刻出现的验证器重新生成验证回调。

这可能吗?如果没有,有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

检查activerecord/lib/active_record/validations/presence.rb的代码可以了解如何实现这一目标:

# File activerecord/lib/active_record/validations/presence.rb, line 60
def validates_presence_of(*attr_names)
  validates_with PresenceValidator, _merge_attributes(attr_names)
end

所以我想我会尝试使用alias_method

挂钩validates_with

alias_method :orig_validates_with :validates_with

现在您有机会获得传递的值,因此您可以将它们存储在某处并在需要在UserForm

上重新创建验证时检索它们
alias_method :orig_validates_with, :validates_with
def validates_with(*args)
  # save the stuff you need, so you can recreate this method call on UserForm
  orig_validates_with(*args)
end

然后您应该可以致电UserForm.validates_with(*saved_attrs)。对不起,这不是你可以复制/粘贴的东西,但这应该让你开始。 HTH