如何将变量传递给布局?

And*_*rew 14 ruby layout ruby-on-rails

我有两个版本的应用程序布局,它们只有几行不同.考虑以下示例:

!!!    
%html
    %head
        # a lot of code here
%body
    # some more code here
    - if defined? flag and flag == true
        # variant 1
    - else
        # variant 2
Run Code Online (Sandbox Code Playgroud)

问题是,如何将此标志传递给布局?

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

    # ...
end
Run Code Online (Sandbox Code Playgroud)

Dan*_*nne 16

在这些情况下,我通常更喜欢使用辅助方法而不是实例变量.以下是如何完成的示例:

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

  ...

protected
  def flag
    true
  end
end
Run Code Online (Sandbox Code Playgroud)

如果你有一个控制器,其中flag不应该是true,那么你只需覆盖该方法:

class PostsController < ApplicationController
  ...

private
  def flag
    false # or perhaps do some conditional
  end
end
Run Code Online (Sandbox Code Playgroud)

这样,您可以确保标记帮助程序始终在视图中可用,因此您不必执行此操作if defined?或任何操作,并且在没有使用布局的情况下,也不会在任何实例中分配实例变量before_filter.

它还有助于在视图中保留尽可能少的实例变量.


And*_*rew 13

好的,所以我自己找到了解决方案:

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

    def set_constants
        @flag = true
    end
end
Run Code Online (Sandbox Code Playgroud)

模板应该是:

!!!    
%html
    %head
        # a lot of code here
%body
    # some more code here
    - if @flag
        # variant 1
    - else
        # variant 2
Run Code Online (Sandbox Code Playgroud)

  • 这就是我所说的,使用控制器实例变量.不确定是"自己动手",虽然我很高兴它正在发挥作用. (2认同)

Dav*_*ton 8

控制器实例变量?这是获取模板信息的常用方法.

  • 不要使用"flag"---使用"@flag" (3认同)
  • 如果要传递多个变量,将它们捆绑在散列或对象中可能会很方便,这些散列或对象可以在需要该布局的所有方法中重用。 (2认同)

p11*_*00i 8

还有另外两个选择,OP实际上是什么问题:

#1

在你的布局中:

- if flag ||= false
  # variant 1
- else
  # variant 2
Run Code Online (Sandbox Code Playgroud)

在您的应用程序控制器中(这是技巧):

layout 'application' # or whatever
Run Code Online (Sandbox Code Playgroud)

在任何类型的控制器:

render :locals => { :flag => true }
Run Code Online (Sandbox Code Playgroud)

我的猜测是,布局处理后来发生了"动态"(不是真正的)layout定义,并为内部的所有键生成必要的方法local_assigns.因此,实例变量可能是一种性能解决方案.有什么想法吗?请发表评论.

#2

您可以使用如下local_assigns变量:

- if local_assigns[:flag] ||= false
  # variant 1
- else
  # variant 2
Run Code Online (Sandbox Code Playgroud)

然后在你的任何一个控制器中:

render :locals => { :flag => true }
Run Code Online (Sandbox Code Playgroud)