Есть ли способ проверить конкретный атрибут в ActiveRecord без создания экземпляра объекта?
Например, если у меня есть модель пользователя, и мне нужно проверить только авторизацию (которая может произойти при проверке формы через ajax), было бы замечательно, если бы я использовал те же проверки модели, которые были определены в модели User, без фактического создания пользовательский экземпляр.
Итак, в контроллере я могу написать код, например
User.valid_attribute?(:login, "login value")
В любом случае я могу это сделать?
Ответы
Ответ 1
Поскольку проверки действуют на экземпляры (и они используют атрибут ошибок экземпляра в качестве контейнера для сообщений об ошибках), вы не можете использовать их, не создавая экземпляр объекта. Сказав это, вы можете скрыть это поведение в методе класса:
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, чтобы он был доступен для каждой модели.)
Ответ 2
Спасибо Милан за ваше предложение. Вдохновленный им, я создал простой модуль, который можно использовать, чтобы добавить эту функциональность в любой класс. Обратите внимание, что исходное предложение Milans имеет логическую ошибку в виде строки:
return mock.errors.has_key?(attr)
должно быть ясно:
return (not mock.errors.has_key?(attr))
Я тестировал свое решение, и оно должно работать, но я не даю никаких гарантий. И вот мое славное решение. В принципе, 2-футовый, если вы убираете материал модуля.. Он принимает имена методов как укусы или символы.
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
Ответ 3
Чтобы использовать стандартные стандартные процедуры проверки:
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
Ответ 4
У меня было чертовски время заставить это работать в 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
Ответ 5
Я пошел с пользовательским решением класса, но я просто хотел убедиться, что нет лучшего способа
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
и я могу использовать его как
valid, errors = ModelValidator.validate_attribute (Пользователь, "login", "humanzz" )
Ответ 6
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), чтобы узнать, действительно ли логин
Ответ 7
Реализация метода 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
Ответ 8
Как насчет:
User.columns_hash.has_key? ( 'Войти')