Использование content_for внутри контроллера

#ruby-on-rails-3

#ruby-on-rails-3

Вопрос:

Это странное требование, для которого может потребоваться другой подход, но мой мозг застрял.

Я хочу выполнить что-то вроде этого:

 class UsersController < ApplicationController
  before_filter Proc.new { share_params :user_name }, :only => :show
  render_djs
end

class ApplicationController < ActionController::Base
  include ActionView::Helpers::CaptureHelper
  def share_params(*shared)
    content_for(:djs) { shared.inspect }
  end

  def self.render_djs
    before_filter Proc.new {
      render :inline => "<%= yield(:djs) %>" if request.format.djs?
    }
  end
end
  

Я хочу использовать, content_for потому что я могу захотеть добавить содержимое в :djs результат в других фильтрах.

Однако этот код вызывает undefined method output_buffer= .

Полагаю, я мог бы использовать переменную экземпляра, но это кажется более чистым, не так ли?

Комментарии:

1. Для будущих читателей обратитесь к ответу @Camden, используя переменную экземпляра, переданную в представление. Контроллеры не должны знать, что вы хотите сделать со своей информацией, а просто передавать ее в представление (и content_for() это функция представления). Это не зря называется «Model-View-Controller».

Ответ №1:

Вам нужно использовать #view_context метод для доступа к контексту представления, а затем вы можете делать то же самое, что и в представлении:

 view_context.content_for(:something, view_context.render(partial: 'some_partial'))
  

Комментарии:

1. … по-видимому, ни в Rails 5.

2. @CyrilDuchon-Дорис Кристиан Привет, ребята, смотрите мой ответ выше.

Ответ №2:

вы не можете использовать content_for в контроллерах, даже если вы знали, что view_context можете предоставить метод. смотрите проблему здесь:https://github.com/rails/rails/issues/4906

метод view_context всегда возвращает новый объект. при вызове view_context.content_for(:somethin, 'content') он сохранит содержимое в переменной экземпляра нового объекта.

вы можете провести эксперимент в контроллерах, подобных следующему:

 view_context.content_for(:title, 'hello')
view_context.view_flow.content # => {}

a = view_context
a.content_for(:title, 'hello')
a.view_flow.content # =>  {:title=>"hello"}
  

в любом случае, если вы все еще хотите использовать content_for в контроллерах, вы можете переопределить view_context в контроллерах в качестве обходного пути. но я не знаю, есть ли какие-либо побочные эффекты.

 def view_context
  @_view_context ||= super
end
  

Комментарии:

1. Пока что обходной путь в Rails 7.0.3 выглядит нормально. Я собираюсь использовать это и обновлю, если обнаружу скрытую ошибку (например, с turbo …)

Ответ №3:

Я нашел это очень полезным в случае настройки заголовка для моей страницы.

Я могу просто установить content_for из контроллера

 class PostsController < ApplicationController
  def index
    content_for :title, "List of posts"
    ...
  end
end
  

https://gist.github.com/hiroshi/985457
https://github.com/clmntlxndr/content_for_in_controllers

Комментарии:

1. Пробую это в данный момент и, по крайней мере, на Rails 3.2, это не работает. content_for(:title) из представления работает, но из контроллера, похоже, уходит в черную дыру.

2. вы пытались добавить этот драгоценный камень? github.com/clmntlxndr/content_for_in_controllers

3. Я не добавлял сам gem, но я взял его код, чтобы посмотреть, работает ли он. Похоже, что Rails начал стирать контекст представления между вызываемым контроллером и отображаемым шаблоном, поэтому контекстный массив, который вы задаете из контроллера, не используется из представления. В любом случае, я закончил тем, что использовал что-то намного более простое, установив @title из контроллера, а затем попросил view выполнить content_for.

4. Большое вам спасибо за публикацию этого! Я смог использовать это решение для переопределения заголовков моих страниц. Приветствия.

Ответ №4:

Если, как и я, вы просто хотите задать содержимое в контроллере в виде заголовка, то, вероятно, лучше просто использовать переменную, которая автоматически передается представлениям и помощникам. например.

контроллер:

 class AController < ApplicationController
  before_action :set_title
  private
    def set_title
      @title = 'Email Subscription'
    end
end
  

и помощник:

 module ApplicationHelper
  def title_suffix
    " - #{@title}" unless @title.nil?
  end
end
  

и шаблон:

 <!DOCTYPE html>
<html>
<head>
  <title>Standard Title<%= title_suffix %></title>
...
  

Ответ №5:

Я нашел более чистый способ, чем установка content_for из контроллера.

В моем случае у меня есть боковая панель, которая должна отображаться для каждого просмотра.

В моем макете у меня есть

 <%= yield :sidebar %>
  

Тогда у меня есть частичное вызываемое _set_sidebar.html.erb , которое делает это

 <% content for :sidebar do %>
   <% render :partial => "layouts/sidebar", locals => {:locs => locs} %>
<% end %>
  

Затем я просто добавляю однострочную строку в каждое представление, в котором я хочу также иметь эту боковую панель

 <%= render :partial => "layouts/set_sidebar", locals => {:locs => locs}
  

В противном случае я ранее использовал это

https://gist.github.com/985457 с .html_safe, когда я использовал render_to_string

Комментарии:

1. «Затем я просто добавляю однострочную строку в каждое представление, в котором я хочу также иметь эту боковую панель», Для этого и существуют макеты (для будущих читателей).

Ответ №6:

view_context не сработало в 5.1.4

render inline: erb однако, сделал:

 
    render inline: <<~ERB, layout: 'layout_expecting_subtabs'
      <% content_for(:subtabs, render(partial: 'somewhere/subtabs') )  %>
      <h1> yielded content </h1>
    ERB