Есть ли способ проверить конкретный атрибут в 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? ( 'Войти')