Почему я не могу сделать "если ноль" в рубине?

>> current_user.first_visit
=> 0
>> if current_user.first_visit
>> puts "test"
>> end
test
=> nil

Почему он печатает тест?

Ответ 1

В Ruby только nil можно считать аналогом false. Нет предположения, что 0, "" или [] означает false, поэтому вы должны использовать == 0, .blank?, .empty?, .zero? и т.д.

Но nil не всегда ведет себя как false. Например, при строчной интерполяции метод .to_s применяется к содержимому #{}, который работает по-разному для FalseClass и NilClass:

irb(main)> "qwe #{false} rty"
=> "qwe false rty"
irb(main)> "qwe #{nil} rty"
=> "qwe  rty"

Ответ 2

Вы можете думать о Ruby, если в качестве тестирования логического или для доступности данных (vs nil). Неявное преобразование от 0 к ложному, поддерживаемое C и (следовательно, другие языки, такие как С++), было более историческим артефактом за несколько дней до того, как C имел отчетливый булевский тип. Там он полагается на то, что 0 является удобной дозорной величиной или имеет интуитивное значение. Для многих вещей (например, в какой-то стране, где размеры одежды варьируются от 0 до 8, результаты вызова функции POSIX libC), ноль не преобразуется красиво в логически эквивалентное булево, поэтому не так уж плохо, что Ruby идет своим путем.

С этой точки зрения проблема с вашим кодом заключается в том, что current_user.first_visit - имя которого подразумевает логический тип - фактически содержит 0, а не false. В качестве альтернативы, если у вас есть явно числовой current_user.visit_counter, было бы естественно и правильно использовать один из:

current_user.visit_counter > 0
current_user.visit_counter >= 1
current_user.visit_counter != 0

Ответ 3

Вы можете попробовать это

>> current_user.first_visit
=> 0
>> if current_user.first_visit != 0
>> puts "test"
>> else
>> puts "fail"
>> end
fail
=>nil

При проверке числовых значений вам также необходимо сопоставить его с ожидаемым значением