Как передать переменную в макет?

У меня есть две версии моего макета приложения, которые отличаются только несколькими строками. Рассмотрим следующий пример:

!!!    
%html
    %head
        # a lot of code here
%body
    # some more code here
    - if defined? flag and flag == true
        # variant 1
    - else
        # variant 2

Вопрос в том, как передать этот флаг в макет?

class ApplicationController < ActionController::Base
    layout 'layout', :locals => {:flag => true} #won't work :(

    # ...
end

Ответ 1

Переменная экземпляра контроллера? Это нормальный способ получения информации в шаблон.

Ответ 2

Обычно я предпочитаю использовать вспомогательные методы вместо переменных экземпляра в этих ситуациях. Вот пример того, как это можно сделать:

class ApplicationController < ActionController::Base
  layout 'layout'
  helper_method :flag

  ...

protected
  def flag
    true
  end
end

И если у вас есть контроллер, где флаг не должен быть правдой, вы просто перезаписываете метод:

class PostsController < ApplicationController
  ...

private
  def flag
    false # or perhaps do some conditional
  end
end

Таким образом, вы убедитесь, что хелпер флага всегда доступен в представлениях, поэтому вам не нужно делать if defined? или что-то еще, а также в тех случаях, когда макет не используется, тогда никакая переменная экземпляра не назначается в любой before_filter.

Он также помогает хранить как можно меньше переменных экземпляра в представлениях.

Ответ 3

Хорошо, поэтому я нашел решение самостоятельно:

class ApplicationController < ActionController::Base
    layout 'layout'
    before_filter :set_constants

    def set_constants
        @flag = true
    end
end

И шаблон должен быть:

!!!    
%html
    %head
        # a lot of code here
%body
    # some more code here
    - if @flag
        # variant 1
    - else
        # variant 2

Ответ 4

Существует еще два варианта, что на самом деле запросил OP:

# 1

в вашем макете:

- if flag ||= false
  # variant 1
- else
  # variant 2

в вашем прикладном контроллере (это трюк):

layout 'application' # or whatever

в любом контроллере:

render :locals => { :flag => true }

Я предполагаю, что обработка макета происходит позже из-за "динамического" (не реально) определения layout и генерирует необходимые методы для всех ключей внутри local_assigns. Так что, возможно, переменная экземпляра является решением для исполнителей. Любые мысли об этом? Пожалуйста, оставьте комментарий.

# 2

Вы можете просто использовать переменную local_assigns, например:

- if local_assigns[:flag] ||= false
  # variant 1
- else
  # variant 2

а затем в любом из ваших контроллеров:

render :locals => { :flag => true }