Ответ 1
Я делаю это:
<% some_local = default_value if local_assigns[:some_local].nil? %>
Я был плохим парнем и использовал следующий синтаксис в своих частичных шаблонах для установки значений по умолчанию для локальных переменных, если значение не было явно определено в хеше locals при рендеринге частичного
<% foo = default_value unless (defined? foo) %>
Кажется, что это было хорошо до недавнего времени, когда (без каких-либо причин я мог различить), не прошедшие переменные начали вести себя так, как если бы они были определены как nil (а не undefined).
Как было указано различными полезными людьми на SO, http://api.rubyonrails.org/classes/ActionView/Base.html говорит, что не использовать
defined? foo
и вместо этого использовать
local_assigns.has_key? :foo
Я пытаюсь изменить свои способы, но это означает изменение большого количества шаблонов.
Можно/должен ли я просто заряжать вперед и внести это изменение во все шаблоны? Есть ли какая-то хитрость, на которую мне нужно следить? Насколько усердно мне нужно проверить каждый?
Я делаю это:
<% some_local = default_value if local_assigns[:some_local].nil? %>
Так как local_assigns
является хешем, вы также можете использовать fetch с опцией default_value
.
local_assigns.fetch :foo, default_value
Это вернет default_value
, если foo
не был установлен.
ВНИМАНИЕ:
Будьте осторожны с local_assigns.fetch :foo, default_value
, когда default_value
- это метод, так как он будет вызываться в любом случае, чтобы передать его результат на fetch
.
Если ваш default_value
- это метод, вы можете обернуть его в блок: local_assigns.fetch(:foo) { default_value }
, чтобы предотвратить его вызов, когда он не нужен.
Как насчет
<% foo ||= default_value %>
Это говорит: "Используйте foo
, если это не nil или true. В противном случае назначьте default_value
foo"
Я думаю, это нужно повторить здесь (из http://api.rubyonrails.org/classes/ActionView/Base.html):
Если вам нужно выяснить, была ли назначена определенная локальная переменная определенному в конкретном вызове рендеринга, вам нужно использовать следующий шаблон:
<% if local_assigns.has_key? :headline %>
Headline: <%= headline %>
<% end %>
Тестирование с использованием определенных? заголовок не будет работать. Это ограничение реализации.
Я знаю, что это старый поток, но здесь мой небольшой вклад: я использовал бы local_assigns[:foo].presence
в условном внутри частичного.
Затем я устанавливаю foo
только в случае необходимости в вызове рендеринга:
<%= render 'path/to/my_partial', always_present_local_var: "bar", foo: "baz" %>
Посмотрите на официальное руководство Rails здесь . Действителен с RoR 3.1.0.
Я думаю, что это лучший вариант, который позволяет использовать несколько переменных по умолчанию:
<% options = local_assigns.reverse_merge(:include_css => true, :include_js => true) %>
<%= include_stylesheets :national_header_css if options[:include_css] %>
<%= include_javascripts :national_header_js if options[:include_js] %>
Это производная от ответа Пабло. Это позволяет установить значение по умолчанию ( "полный" ), и в конце "режим" устанавливается как в local_assign, так и в локальной локальной переменной.
Haml/тонкий:
- mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full')
Еврорадио:
<% mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full') %>
В моем случае я использую:
<% variable ||= "" %>
в моем частичном.
У меня нет идеи, если это хорошо, но для меня все в порядке.
Более интуитивно понятный и компактный:
<% some_local = default_value unless local_assigns[:some_local] %>
Если вы не хотите передавать локальную переменную в частичную при каждом ее вызове, вы делаете это:
<% local_param = defined?(local_param) ? local_param : nil %>
Таким образом вы избегаете ошибки undefined variable
. Это позволит вам называть ваши частичные с/без локальных переменных.
Помощник может быть создан таким образом:
somearg = opt(:somearg) { :defaultvalue }
Реализовано как:
module OptHelper
def opt(name, &block)
was_assigned, value = eval(
"[ local_assigns.has_key?(:#{name}), local_assigns[:#{name}] ]",
block.binding)
if was_assigned
value
else
yield
end
end
end
Подробнее о том, как и почему, см. мой блог.
Обратите внимание, что это решение позволяет вам передавать nil или false как значение без его переопределения.