определен?метод в Ruby и Rails
-
04-07-2019 - |
Вопрос
У меня есть довольно старая система шаблонов, написанная поверх ERB.Он опирается на шаблоны ERB, хранящиеся в базе данных.Они считываются и визуализируются.Когда я хочу передать данные из одного шаблона в другой, я использую параметр:locals для метода Rails render.Для установки переменных по умолчанию для этих переменных в некоторых шаблонах я использую определенный?метод, который просто сообщает мне, была ли определена локальная переменная, и если нет, я инициализирую ее значением по умолчанию следующим образом:
unless defined?(perex)
perex = true
end
Я обновляю приложение до последней версии Rails и вижу какое-то странное поведение.В принципе, это иногда работает (иногда perex не определено), а иногда и нет (perex определен и имеет значение nil).Это происходит без каких-либо изменений.
У меня есть два вопроса:Есть ли какой-нибудь лучший способ, кроме использования defined?что доказывает свою ненадежность (было надежным в течение нескольких лет на top Rails 1.6)?Такой способ не должен приводить к тому, что я буду переписывать все шаблоны.Я просматривал документы Ruby и не смог найти ничего о defined?способ.Было ли это устаревшим, или я просто слепой?
Редактировать: Фактическая проблема была вызвана тем, что, по-видимому, является ошибкой Ruby / eRB.Иногда если не утверждение могло бы сработать, но иногда нет.Самое странное, что даже если вторая строка была выполнена перекс по-прежнему оставался нулем для остального мира.Удаление определено?решил это.
Решение
Первый:на самом деле, defined?
является оператором.
Второй:если я правильно понимаю ваш вопрос, способ сделать это - использовать эту идиому Ruby:
perex ||= true
Это присвоит true значение perex
если это не определено или nil
.Это не совсем то, что делает ваш пример, поскольку ваш не оценивает присваивание, когда значение равно nil
, но если вы полагаетесь на это, то, на мой взгляд, не видя этого, вы не пишете понятный код.
Редактировать:Как отметил Хонза, приведенное выше утверждение заменит значение perex
когда это false
.Тогда я предлагаю переписать минимальное количество строк следующим образом:
perex ||= perex.nil? # Assign true only when perex is undefined or nil
Другие советы
Самый безопасный способ проверить, определен ли локальный файл в шаблоне Rails, - это:
local_assigns[:perex]
Это задокументировано в Rails API вместе с объяснением, что defined?
не может быть использован из-за ограничения реализации.
Согласно ответу мислава, я искал эту документацию в Rails API и нашел ее в Класс ActionView::База (под заголовком "Передача локальных переменных во вложенные шаблоны").Однако вряд ли стоило искать, поскольку в нем говорилось едва ли больше, чем в миславе.За исключением того, что он рекомендует этот шаблон:
if local_assigns.has_key? :perex
Принимая во внимание оригинальный ответ мислава и Разработка Кенба, Я думаю, что следующий подход является абсолютно лучшим (хотя я открыт для мнений).Он использует Ruby's Хэш#выборка метод резервного копирования альтернативного значения, если ключ не существует в исходном хэше.
perex = local_assigns.fetch(:perex, true)
Это даже лучше, чем ||=
метод, который предложит большинство пользователей, поскольку иногда вам захочется разрешить false
ценности.Например, следующий код будет никогда разрешить false
значение, которое должно быть передано в:
perex = local_assigns[:perex] || true