Подтвердить что ты не робот

Как проверить, какая проверка не выполнена в ActiveRecord?

У меня есть такая модель:

class User < ActiveRecord::Base
  validates_length_of :name, :in => (2..5)
end

Я хочу проверить это подтверждение:

it "should not allow too short name" do
  u = User.new(:name => "a")
  u.valid?
  u.should have(1).error_on(:name)
end

Но тогда он не проверяет, какая ошибка была установлена ​​на name. Я хочу знать, если это было too_short, too_long, или, возможно, какая-то другая проверка не удалась.

Я могу найти текст сообщения в массиве ошибок, например:

u.errors[:name].should include(I18n.t("activerecord.errors.models.user.attributes.name.too_short"))

Но это не удастся, если я установил activerecord.errors.messages.too_short в файл локали вместо сообщения, специфичного для модели.

Итак, можно ли проверить, какая ошибка произошла?

4b9b3361

Ответ 1

Rails добавлен метод запроса ошибок для ActiveModel в конце 2011 года и Rails v3.2. Просто проверьте, была ли соответствующая ошибка #added?:

# An error added manually
record.errors.add :name, :blank
record.errors.added? :name, :blank # => true

# An error added after validation
record.email = '[email protected]'
record.valid? # => false
record.errors.added? :email, :taken # => true

Обратите внимание, что для параметризуемых валидаций (например, :greater_than_or_equal_to) вам также необходимо передать значение параметра.

record.errors.add(:age, :greater_than_or_equal_to, count: 1)
record.errors.added?(:age, :greater_than_or_equal_to, count: 1)

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

Некоторые другие полезные вопросы, которые вы можете задать ActiveModel#Error, #empty? и #include?(attr), а также все, что вы можете задать Enumerable.

Ответ 2

Мне действительно не нравится идея перевода переведенных сообщений об ошибках в хэш ошибок. После разговора с коллегами-рубистами я закончил обезглавливать хэширование ошибок, поэтому сначала сохраняет неизменяемое сообщение.

module ActiveModel
  class Errors
    def error_names
      @_error_names ||= { }
    end

    def add_with_save_names(attribute, message = nil, options = {})
      message ||= :invalid
      if message.is_a?(Proc)
        message = message.call
      end
      error_names[attribute] ||= []
      error_names[attribute] << message
      add_without_save_names(attribute, message, options)
    end

    alias_method_chain :add, :save_names
  end
end

Затем вы можете протестировать следующим образом:

u = User.new(:name => "a")
u.valid?
u.errors.error_names[:name].should include(:too_short)

Ответ 3

Я рекомендую проверить gem shoulda для обработки этих типов повторных тестов проверки. Он дополняет RSpec или Test:: Unit, поэтому вы можете написать краткие спецификации, такие как:

describe User do
  it { should ensure_length_of(:name).is_at_least(2).is_at_most(5) }
end

Ответ 4

Подход, который я использую:

it "should not allow too short name" do
  u = User.new(:name => "a")
  expect{u.save!}.to raise_exception(/Name is too short/)
end

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

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