例如,如果我有一个用户模型并且我只需要验证登录(这可能在通过 ajax 验证表单时发生),如果我使用在用户模型中定义的相同模型验证而不实际实例化用户实例,那就太好了.
所以在控制器中我可以编写类似的代码
User.valid_attribute?(:login, "login value")
无论如何我可以做到这一点吗?
例如,如果我有一个用户模型并且我只需要验证登录(这可能在通过 ajax 验证表单时发生),如果我使用在用户模型中定义的相同模型验证而不实际实例化用户实例,那就太好了.
所以在控制器中我可以编写类似的代码
User.valid_attribute?(:login, "login value")
无论如何我可以做到这一点吗?
由于验证对实例进行操作(并且它们使用实例的 errors 属性作为错误消息的容器),因此您不能在没有实例化对象的情况下使用它们。话虽如此,您可以将这种需要的行为隐藏到类方法中:
class User < ActiveRecord::Base
def self.valid_attribute?(attr, value)
mock = self.new(attr => value)
unless mock.valid?
return mock.errors.has_key?(attr)
end
true
end
end
现在,您可以致电
User.valid_attribute?(:login, "login value")
正如你所愿。
(理想情况下,您应该将该类方法直接包含在 ActiveRecord::Base 中,这样它就可用于每个模型。)
谢谢米兰的建议。受此启发,我创建了一个简单的模块,可用于将此功能添加到任何类。请注意,最初的 Milans 建议有一个逻辑错误,如下所示:
return mock.errors.has_key?(attr)
显然应该是:
return (not mock.errors.has_key?(attr))
我已经测试了我的解决方案,它应该可以工作,但我不保证。这是我光荣的解决方案。如果你拿走模块的东西,基本上是一个 2-liner。它接受方法名称作为字符串或符号。
module SingleAttributeValidation
def self.included(klass)
klass.extend(ClassMethods)
end
module ClassMethods
def valid_attribute?(attr, value)
mock = self.new(attr => value)
(not mock.valid?) && (not mock.errors.has_key?(attr.class == Symbol ? attr : attr.to_sym))
end
end
end
要使用您的标准验证例程:
User.new(:login => 'login_value').valid?
如果这对您不起作用,请为此构建一个自定义类方法:
class User < ActiveRecord::Base
validate do |user|
user.errors.add('existing') unless User.valid_login?(user.login)
end
def self.valid_login?(login)
# your validation here
!User.exist?(:login=> login)
end
end
我花了很长时间让它在 Rails 3.1 中工作。这终于奏效了。(不确定这是否是最好的方法,我是新手。)。我遇到的问题是该值被设置为 ActiveSupport::SafeBuffer 类型,并且验证失败。
def self.valid_attribute?(attr, value)
mock = User.new(attr => "#{value}") # Rails3 SafeBuffer messes up validation
unless mock.valid?
return (not mock.errors.messages.has_key?(attr))
end
return true
end
我已经使用了自定义类解决方案,但我只是想确保没有更好的方法
class ModelValidator
def self.validate_atrribute(klass, attribute, value)
obj = Klass.new
obj.send("#{attribute}=", value)
obj.valid?
errors = obj.errors.on(attribute).to_a
return (errors.length > 0), errors
end
end
我可以像使用它一样
有效,错误 = ModelValidator.validate_attribute(User, "login", "humanzz")
class User < ActiveRecord::Base
validates_each :login do |record, attr, value|
record.errors.add attr, 'error message here' unless User.valid_login?(value)
end
def self.valid_login?(login)
# do validation
end
end
只需调用 User.valid_login?(login) 即可查看登录本身是否有效
您建议的“valid_attribute”方法的实现:
class ActiveRecord:Base
def self.valid_attribute?(attribute, value)
instance = new
instance[attribute] = value
instance.valid?
list_of_errors = instance.errors.instance_variable_get('@errors')[attribute]
list_of_errors && list_of_errors.size == 0
end
end
怎么样:
User.columns_hash.has_key?('login')