Проверка включения Rails

Я борюсь со следующей проверкой включения,

class User < ActiveRecord::Base
  attr_accessible :language

  validates :language, :presence => true, :inclusion => { :in => I18n.available_locales.join(' ')}
end

Если я запущу это в консоли,

u = User.new
u.valid?

затем я получаю TypeError: can't convert nil into String в методе include? active_model/validations/inclusion.rb.

Однако, если я изменю строку проверки на

validates :language, :presence => true, :inclusion => { :in => %(en fr es)}

тогда проверка работает как положено. Это недопустимо, если язык равен нулю или не является одной из записей в списке, как вы ожидаете, и нет сбоя.

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

Я даже пытался использовать proc форму :in, чтобы увидеть, имеет ли это какое-то значение, но это не так. Но тогда я действительно не ожидал, что это понадобится, потому что я хочу сгенерировать список только один раз, когда приложение все равно загружается, поскольку I18n.available_locales никогда не изменится во время выполнения приложения.

ОБНОВЛЕНИЕ: у меня возникла идея, и я протестировал следующий код:

class User < ActiveRecord::Base
  attr_accessible :language

  validates :language, :presence => true, :inclusion => { :in => ['en','fr','es'].join(' ') }
end

Этот код также генерирует ту же ошибку, поэтому проблема не в I18n или чем-то подобном. Это связано с разницей между %(en fr es) и ['en','fr','es'].join(' ').


person richard    schedule 30.09.2012    source источник


Ответы (2)


Причина, по которой работает ваше второе условие, заключается в том, что #include? определено для класса String:

> "qwertyuiop".include? "tyu"
true

поэтому, если вы подтвердите включение в %(en fr es) (что точно равно "en fr es"), значение "n f" пройдет проверку.

Вы должны использовать массив (либо как литерал [], либо как слова %w()). Если вы хотите использовать I18n.available_locales, обязательно преобразуйте их в строки.

validates :language, :inclusion => { :in => I18n.available_locales.map(&:to_s) }

Я не могу воспроизвести вашу ошибку, но проверка :presence бесполезна, так как :inclusion уже проверяет наличие значения в списке.

person rewritten    schedule 30.09.2012

Вы должны передать массив в проверку inclusion, а не строку. Итак, в вашем примере с %(en fr es), если вы используете %w(en fr es), все работает нормально.

person Vasiliy Ermolovich    schedule 30.09.2012