необов'язкові локальні змінні в часткових шаблонах рейок: як мені вийти з (визначеного? foo) безладу?


225

Я був поганою дитиною і використовував наступний синтаксис у своїх часткових шаблонах для встановлення значень за замовчуванням для локальних змінних, якщо значення не було чітко визначено в:

<% foo = default_value unless (defined? foo) %>

Це, здавалося, спрацювало нормально до недавнього часу, коли (з якихось причин я не міг розрізнити) непередані змінні почали поводитись так, ніби вони були визначені нульовими (а не визначеними).

Як вже вказували різні корисні люди в програмі SO, http://api.rubyonrails.org/classes/ActionView/Base.html говорить, що не використовувати

defined? foo

і замість цього використовувати

local_assigns.has_key? :foo

Я намагаюся внести зміни в свої способи, але це означає змінити багато шаблонів.

Чи можу я / повинен заряджати лише вперед та вносити цю зміну у всі шаблони? Чи є якась хитрість, яку мені потрібно стежити? Як старанно мені потрібно перевірити кожного?

Відповіді:


324

Я роблю це:

<% some_local = default_value if local_assigns[:some_local].nil? %>

1
Хоча мені дуже подобається компактний синтаксис пропозиції hgimenez (вище), цей підхід має перевагу в тому, щоб бути дуже зрозумілим: що відбувається. (Все ще є недолік того, що ви не дозволяєте вам здати нуль як значення для місцевих)
бран

1
Який ваш випадок використання для того, щоб хочете перейти нуль?
jonnii

О, я не маю на увазі конкретного випадку. Просто намагаюся зрозуміти всі наслідки. Це нагадало мені прийняти цю відповідь :-)
бран

4
Щоб вирішити проблему з нулем, я копіюю код із посилання ОП ( api.rubyonrails.org/classes/ActionView/Base.html ) <%, якщо local_assigns.has_key? : headline%> Title: <% = headline%> <% end%> - has_key дозволяє уникнути нульової / хибної ситуації, і, ймовірно, її можна скоротити до одного рядка, як відповідь тут
Phil

5
Перевірте відповідь Пабло: local_assigns.fetchпрекрасно обробляє навіть клавіші з нульовим значенням. Він повертає за замовчуванням лише в тому випадку, якщо ключ зовсім не встановлений.
quetzalcoatl

158

Оскільки 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 }щоб запобігти його виклику, коли він не потрібен.


1
Варто сказати це прямо: nilзначення зберігаються тут. Якщо хеш містить :fooвідображення nil, fetchвін повернеться nil. Тобто, принаймні, на моєму v1.9.3. Я не пам'ятаю, як поводився 1,8.
quetzalcoatl

Це абсолютно правильно. Він пам'ятає мені проблему local_assigns[:foo] || default_value, коли foo повертає помилкове значення, default_valueзамість цього буде використано. Як правило, проблема пам'яті, @some_value ||= expensive_methodякщо метод повертає помилкове значення, завжди буде виконуватися.
Пабло Кантеро

1
Той, хто не розуміє, чому це найкраща відповідь, недостатньо довго використовував рубін. Браво Пабло!
mastaBlasta

2
Оптимізація полягає в наступному, так що вам потрібно буде викликати це лише один раз у верхній частині шаблону, а не використовувати "охорону для отримання" при кожному використанні змінної. foo ||= local_assigns[:foo] = local_assigns.fetch(:foo, default_value)
sethcall

Мені було цікаво, чому це не працює, я припустив, що він також створив змінну, але ми все одно повинні використовувати повернене значення:foo = local_assigns.fetch :foo, true
Vadorequest

84

Як щодо

<% foo ||= default_value %>

Це говорить "використовувати, fooякщо це не нульове або істинне. Інакше призначити default_valuefoo"


2
Я не впевнений, що це працює, оскільки foo не визначено, якщо він не передається через локальний хеш.
jonnii

1
Це працює, але якщо у вас є такі значення за замовчуванням, як це, можливо, це знак того, що вам слід скористатися помічником?
психо

2
Тут немає ніякої магії. Більше ресурсів на тему: groups.google.com/group/comp.lang.ruby/browse_thread/thread/…
hgmnz

37
Мені дуже подобається ця версія, оскільки синтаксис такий компактний. Я припускаю, що великим недоліком є ​​те, що це означає, що ви не можете передати нуль або false як значення для локальних, хоча це буде перезаписано за замовчуванням.
бран

16
@brahn, це хороший момент. Насправді цього слід уникати, якщо fooє булевим. Він може по праву мати значення falseта бути default_valueвипадково відмінений .
hgmnz

10

Я думаю, що це слід повторити тут (з http://api.rubyonrails.org/classes/ActionView/Base.html ):

Якщо вам потрібно з’ясувати, чи певній локальній змінній було присвоєно значення в певному виклику візуалізації, вам потрібно скористатись такою схемою:

<% if local_assigns.has_key? :headline %>
  Headline: <%= headline %>
<% end %>

Тестування з використанням визначених? заголовок не працюватиме. Це обмеження щодо реалізації.


6

У моєму випадку я використовую:

<% variable ||= "" %>

в моєму частковому.
Я не маю уявлення, чи це добре, але для мене це нормально


Це насправді працює досить добре. Працює для невизначених і при проходженні nilяк локальний і в частковому дзвінку.
Джошуа Пінтер

3
Ах, прочитавши нижче, це не вдасться, якщо variableце булеве значення, і вам потрібно встановити його false. Він використовуватиме значення за замовчуванням замістьfalse значення. ВИКОРИСТОВУЙТЕ ВАШ ВЛАСНИЙ РИЗИК
Джошуа Пінтер

5

Я знаю , що це стара нитку , але ось мій невеличкий внесок: я хотів би використовувати local_assigns[:foo].presenceв Conditional всередині парціальний. Тоді я встановлюю fooлише тоді, коли це потрібно у виклику візуалізації:

<%= render 'path/to/my_partial', always_present_local_var: "bar", foo: "baz" %>

Ознайомтеся з офіційним посібником з рейок тут . Дійсно з RoR 3.1.0.


Я не бачу реальної різниці між local_assigns[:foo]і local_assigns[:foo].presence. Або повернеться, nilякщо ключ не існує в хеші, а значення, якщо воно існує.
jamesmarkcook

1

Я думаю, що кращий варіант, який дозволяє використовувати декілька змінних за замовчуванням:

<% 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] %>

1

Це похідне від відповіді Пабло. Це дозволяє мені встановити за замовчуванням ("full"), і врешті-решт, "mode" встановлюється як у local_assigns, так і у фактичній локальній змінній.

мл / тонкий:

- mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full')

erb:

<% mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full') %>

0

Більш інтуїтивно зрозумілий та компактний:

<% some_local = default_value unless local_assigns[:some_local] %>


3
Я думаю, що це не вдасться, якщо ви зателефонуєте на часткове:locals => {:some_local => false}
березня

0

Якщо ви не хочете передавати локальну змінну частковій щоразу, коли ви її зателефонуєте, зробіть це:

<% local_param = defined?(local_param) ? local_param : nil %>

Таким чином ви уникнете undefined variableпомилок. Це дозволить вам викликати ваш частковий з / без локальних змінних.


АБО local_param = local_param якщо визначено? (
Local_param

0

Рубін 2,5

Ерб

Це можливо, але ви повинні оголосити свої значення за замовчуванням в області.

ЗМІННО слово для заміни.

# index.html.erb
...
<%= render 'some_content', VARIABLE: false %>
...

# _some_content.html.erb
...
<% VARIABLE = true if local_assigns[:VARIABLE].nil? %>
<% if VARIABLE %>
    <h1>Do you see me?</h1>
<% end %>
...

-6

Помічник може бути створений так:

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

Дивіться мій блог для детальної інформації про те, як і чому.

Зауважте, що це рішення дозволяє передати нульове або хибне значення як значення без його перекриття.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.