在我的用户模型中,我有电子邮件,first_name,last_name,密码等常见的嫌疑人。
我有几种情况需要跳过所有或部分验证。
目前,我有一个看起来类似的条件:
validates :first_name, presence: :true, etc..., unless: :skip_first_name_validation?
validates :last_name, presence: :true, etc..., unless: :skip_last_name_validation?
validates :email, presence: :true, etc..., unless: :skip_email_validation?
当然我也有:
attr_accessor :skip_first_name_validation, :skip_last_name_validation, etc.
然后我使用私有方法来检查每个方法的状态:
def skip_first_name_validation?
skip_first_name_validation
end
def skip_last_name_validation?
skip_last_name_validation
end
def skip_email_validation?
skip_email_validation
end
etc..
从那里,每当我需要跳过验证时,我只是在控制器中为每个人分配一个true
值。
所以这一切都很好,我想知道是否有更优雅的方式?
理想情况下,如果我可以对模型中的每个属性使用这样的简单条件,那将是很好的:
:skip_validation?
在我的控制器中,只需执行以下操作:
skip_validation(:first_name, :last_name, :password) = true
有人可以就我如何编程提出建议吗?我不想使用现有的gem /库,但我想了解如何在rails中编程这种行为。感谢。
答案 0 :(得分:1)
这可以帮助您动态定义所有设置器和检查器
private
def self.skip_validations_for(*args)
# this block dynamically defines a setter method 'set_validations'
# e.g.
# set_validations(true, :email, :last_name, :first_name)
# set_validations(false, :email, :last_name, :first_name)
define_method('set_validations') do |value, *params|
params.each do |var|
self.send("skip_#{var.to_s}_validations=", value)
end
end
# this block walks through the passed in fields and defines a checker
# method `skip_[field_name]_validation?
args.each do |arg|
if self.method_defined? arg
send :define_method, "skip_#{attr.to_s}_validation?" do
send "skip_#{attr.to_s}_validation"
end
end
end
end
然后在您的模型中,无论这是本机中的本机还是通过模块包含,您都可以添加:
Class Foo < ActiveRecord::Base
validate :bar, :presence => true
validate :baz, :length_of => 10
skip_validations_for :bar, :baz
end
此时您可以访问
set_validations(true, :bar, :baz)
和
skip_bar_validation?
<强>更新强>
这段代码会在哪里?
这取决于您希望使用它的程度。如果您只想覆盖一个模型中的验证,那么您可以直接将其全部放在该模型中。但是,如果你想创建一个允许你在每个课程中执行此操作的Module
,那么你必须创建一个Module
将它放在lib/
目录中并确保它在负载路径。也许this可以帮助你。
为什么事情变化如此剧烈?
最初我在实例上使用了_validations方法,这是一个ActiveRecord方法,它返回一个验证哈希值(字段名称 - &gt; ActiveRecord :: Validation)。这种做事方法自动启用了每个领域的能力。允许您选择所需的特定字段是更多Rails'ish。
答案 1 :(得分:0)
我不是元编程方面的专家,但我想你可以实现这样的东西。
class User < ActiveRecord::Base
...
%w(email first_name last_name).each do |attr|
self.send :attr_accessor, "skip_#{attr}_validation".to_sym
self.send :alias, "skip_#{attr}_validation?".to_sym, "skip_#{attr}_validation".to_sym
self.send :validates_presence_of, attr, { unless: "skip_#{attr}_validation?".to_sym }
end
def skip_validation_for(*attrs)
attrs.map{|attr| send "skip_#{attr}_validation=", true }
end
end
并不是很优雅地混合到模型中,但是你可以把它变成一个模块 - 使用可能是这样的:
class User < ActiveRecord::Base
include SkipValidations
skip_validations :email, :first_name, :last_name
end