Есть ли способ проверить определенный атрибут в ActiveRecord, не создавая экземпляр объекта в первую очередь? - PullRequest
10 голосов
/ 19 января 2009

Например, если у меня есть пользовательская модель, и мне нужно только проверять вход в систему (что может произойти при проверке формы через ajax), было бы здорово, если бы я использовал те же проверки модели, определенные в модели User, без фактического создания Пользовательский экземпляр.

Таким образом, в контроллере я мог бы написать код вроде

User.valid_attribute?(:login, "login value")

Могу ли я в любом случае сделать это?

Ответы [ 8 ]

20 голосов
/ 19 января 2009

Поскольку проверки работают с экземплярами (и они используют атрибут ошибок экземпляра в качестве контейнера для сообщений об ошибках), их нельзя использовать без создания экземпляра объекта. Сказав это, вы можете скрыть это необходимое поведение в методе класса:

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, чтобы он был доступен для каждой модели.)

5 голосов
/ 26 октября 2010

Спасибо, Милан, за ваше предложение. Вдохновленный этим, я создал простой модуль, который можно использовать для добавления этой функциональности в любой класс. Обратите внимание, что исходное предложение Милана имеет логическую ошибку в виде строки:

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 голосов
/ 19 января 2009

Чтобы использовать ваши стандартные процедуры проверки:


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
2 голосов
/ 30 октября 2011

У меня было чертовское время заставить это работать в 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
1 голос
/ 19 января 2009

Я выбрал решение для пользовательского класса, но я просто хотел убедиться, что лучшего способа не существует

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 (пользователь, "логин", "человек")

0 голосов
/ 25 февраля 2009

Как насчет:

User.columns_hash.has_key? ( 'Войти')

0 голосов
/ 19 января 2009

Реализация предложенного вами метода '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
0 голосов
/ 19 января 2009
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? (Логин), чтобы узнать, действителен ли сам логин

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...