Rails: проверка включения логического значения не проходит тесты - PullRequest
15 голосов
/ 02 марта 2011

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

После прочтения: Проверка логического значения в Rspec и Rails и Rails: как мне проверить, что что-то является логическим? В итоге я сделал это так:

class Model < ActiveRecord::Base

  validates :my_field, :inclusion => { :in => [true, false] }

end

Я пытался протестировать это несколькими разными способами (используя rspec и musta matchers), и так как мои тесты продолжают терпеть неудачу, я прямо сейчас дошел до самого тупого (?) Способа. Тем не менее, тесты не проходят, и я предполагаю, что есть какой-то механизм, который конвертирует значение куда-то.

Вот что я использую, чтобы узнать, что происходит:

# create instance without setting value ...

# these work as expected
model_instance.valid?.should be_false      # passes
model_instance.my_field = true
model_instance.valid?.should be_true       # passes
model_instance.my_field = false       
model_instance.valid?.should be_true       # passes

# works as expected
model_instance.my_field = ""
model_instance.valid?.should be_false      # passes

# these should pass but fail
model_instance.my_field = "foo"
model_instance.my_field.should == "foo"    # fails as well, my_field == false
model_instance.valid?.should be_false      # fails

model_instance.my_field = "false"
model_instance.my_field.should == "false"  # fails as well, my_field == false
model_instance.valid?.should be_false      # fails

model_instance.my_field = "123"
model_instance.valid?.should be_false      # fails

model_instance.my_field = "true"
model_instance.my_field.should == "true"   # fails as well, my_field == true
model_instance.valid?.should be_false      # fails

Чего мне не хватает? Кажется, значение преобразуется в некоторой логической форме, но где и как это предотвратить? Как правильно выполнить такую ​​проверку?

Ответы [ 2 ]

36 голосов
/ 02 марта 2011

Я не знаю, откуда взялась идея, что вам нужно проверить булево поле как true / false, но я видел это недавно в нескольких не связанных проектах, поэтому я начинаю задумываться, не так лимем, который где-то начался.

Это логическое поле, оно должно быть истинным или ложным.AR заботится о деталях реализации булевых значений для вас.Если вы хотите логическое поле, создайте логическое поле в базе данных.Конец истории.

Глядя на источник, вот код, который преобразует значение в логическое значение:

# File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 147
147:         def value_to_boolean(value)
148:           if value.is_a?(String) && value.blank?
149:             nil
150:           else
151:             TRUE_VALUES.include?(value)
152:           end
153:         end

А вот значения, которые соответствуют их логическим аналогам:

TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set

Итак, еще раз посмотрев на ваш код выше, все так, как должно быть, за исключением того, что вы ожидаете, что это неправильно.присваивая «foo» логическое значение, мы видим, что «foo» отсутствует в списке допустимых истинных значений, поэтому логическое поле по умолчанию имеет значение «false», что позже будет возвращено из его метода доступа.Логическое значение для поля по-прежнему :in => [true, false], поэтому модель действительна.«false» и «123» терпят неудачу по одной и той же причине.«true» является допустимым значением логического значения «true», поэтому для поля устанавливается значение «true» и все еще действует по причине, изложенной выше.

27 голосов
/ 08 июня 2012

Я не гуру Rails, но я выложу здесь свою шею и скажу, что вы действительно хотите проверить логические значения для :inclusion => { :in => [true, false] } - то есть, если вы не хотите разрешать значения nil (NULL).

Исходя из опыта программирования баз данных, я научился помнить, что логическое поле может иметь ТРИ значения: true, false и NULL.При программировании на нативном SQL, NULL требуют специальной обработки (is null вместо = null), что требует много дополнительной работы.

В сегодняшнем тестировании с Rails 3.2 не было проблем с созданием непроверенного логического поля со значением nil и сохранением его в моей базе данных PostgreSQL, где оно должным образом сохранялось как NULL.Чтобы избежать всех проблем, которые могут возникнуть, я планирую использовать этот подход для логических значений в Rails:

  • Определить логические поля с :null => false в миграциях.
  • Использовать :inclusion => { :in => [true, false] } для проверки поля в модели.Это дает хорошее сообщение, если поле неинициализировано (ноль).

Поначалу не интуитивно понятно, что я не могу использовать :presence проверку, но оказывается, :presence проверяет, чтозначение не пустое, а значение false равно пусто.Другими словами, если вы подтвердите :presence => true и установите значение false, проверка завершится неудачей.См. validates_presence_of в API и комментарий @Paul A Jungwirth к ответу @ Karmajunkie.

...