Rails: запутался в синтаксисе передачи локальных данных в партиалы
Понимание Rails "магии" в части рендеринга частичек (и передачи в них локальных).
Почему это работает:
<%= render "rabbits/form" %>
И эта работа:
<%= render "rabbits/form", :parent => @warren, :flash => flash %>
но это не работает
<%= render "rabbits/form", :locals => { :parent => @warren, :flash => flash } %>
Но это делает:
<%= render :partial =>"rabbits/form", :locals => { :parent => @warren, :flash => flash } %>
Кроме того, как я могу найти эти нюансы, чтобы мне не пришлось беспокоить людей на SO?
5 ответов
Краткий ответ: метод render просматривает первый передаваемый аргумент. Если вы передаете хеш (который включает :partial => 'foo', :locals => {blah blah blah}
) тогда он передаст все ваши аргументы как хеш и проанализирует их соответственно.
Если вы передаете строку в качестве первого аргумента, он предполагает, что первый аргумент является вашим частичным именем, а остальная часть будет передаваться как ваши локальные. Однако в последующем вызове он фактически назначает :locals => your_locals_argument
, который в этом случае является целым :locals => {locals hash}
вместо просто {locals hash}
; то есть вы в конечном итоге :locals => {:locals => {locals hash}}
, скорее, чем :locals => {locals hash}
,
Поэтому мой совет - всегда всегда явно передавать значения одним и тем же способом, и у вас не будет проблем. Чтобы узнать об этом, я обратился непосредственно к самому коду (actionpack / lib / base.rb, render()
метод в Rails 2; Рельсы 3 разные). Это хорошее упражнение.
Кроме того, не беспокойтесь о том, чтобы "беспокоить" людей на SO. Вот почему этот сайт существует. Я даже кое-что узнал из этого.
Если вам нужно указать:locals, вам нужно указать: частичный или: шаблон
<%= render :partial => "rabbits/form", :locals => {...} %>
должно сработать
Честно говоря, я знаю только об этих вариантах использования, потому что я не отставал от Rails в течение прошлых нескольких лет и читаю объявления, что был добавлен новый способ сделать это. Я часто ошибаюсь в этом сам, но обычно это легко исправить.
Это одна из тех частей Rails API, которая не была тщательно продумана, если вы спросите меня. Он просто накапливал все больше и больше синтаксического сахара с годами, не осуждая старого поведения. Метод рендеринга имеет диабет.
Что еще хуже, рендер ведет себя по-разному в контроллере и представлении. Я также смотрю на содержимое первого аргумента, чтобы увидеть, является ли он файлом, шаблоном, действием или частичным. Если он начинается с косой черты, то это файл или что-то в этом роде.
Я за использование более коротких обозначений, когда это возможно. Поскольку короткие обозначения действительно сообщают намерение довольно хорошо. При чтении он обычно делает то, что, как вы думаете, он делает. Писать это не так просто.
Вот источник метода рендеринга из http://api.rubyonrails.org/classes/ActionView/Rendering.html:
def render(options = {}, locals = {}, &block)
case options
# Here is your last case
when Hash
if block_given?
_render_partial(options.merge(:partial => options.delete(:layout)), &block)
elsif options.key?(:partial)
_render_partial(options)
else
template = _determine_template(options)
lookup_context.freeze_formats(template.formats, true)
_render_template(template, options[:layout], options)
end
when :update
update_page(&block)
else
# here the first three cases
_render_partial(:partial => options, :locals => locals)
end
end
Надеюсь, это поможет!
У меня были небольшие проблемы с rails 7/ruby 3.2.1, так что для тщательности:
# Works:
<%= render partial: 'publish_unpublish_button', locals: { something: 2, more: 5 } %>
# Works:
<%= render 'publish_unpublish_button', something: 2, more: 5 %>
# Won't work
<%= render 'publish_unpublish_button', locals: { something: 2, more: 5 } %>