如何将变量传递到布局?

17

我有两个应用程序布局版本,它们只在几行代码上有所不同。请看下面的例子:

!!!    
%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
5个回答

18

在这种情况下,我通常更喜欢使用帮助方法而不是实例变量。以下是一个示例,展示了如何实现:

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

  ...

protected
  def flag
    true
  end
end

如果您有一个控制器,其中标志不应为true,则可以覆盖该方法:

class PostsController < ApplicationController
  ...

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

这种方式可以确保在视图中始终可用标志助手,这样您就不必执行if defined?或任何其他操作,同时,在不使用布局的情况下,任何before_filter中都不会分配实例变量。

这还有助于尽可能减少视图中的实例变量数量。


你如何只在某些操作中使用它? 例如,我想仅在“Index”操作中将其设置为“false”。 - eveevans
最简单的方法可能是在方法内部编写 params[:action] != 'index' - DanneManne
在 DanneManne 的回答的基础上,还有一个叫做 action_name 的可用 helper。因此,action_name != 'index' 也可以起作用。(这个 helper 和 controller_name 都是 Rails 提供的)。 - Gal
还有一些辅助模块 - x-yuri

13

好的,我已经自己找到解决方案:

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

1
不要使用 if defined? flag and flag == true,直接使用 if @lite - Jesse Wolgamott
2
这就是我说的,使用控制器实例变量。虽然我不确定这是否是“自己做”,但我很高兴它能够工作。 - Dave Newton
@Dave,你说得对,谢谢。我是Ruby的新手,花了一些时间才找到它实际意义是什么,不幸的是,谷歌没有在第一篇结果中提供清晰的解释。 - Andrew
如果有人想知道before_filter是什么...它与before_action相同。在Rails 5.0中,before_filter语法已被弃用,并将在Rails 5.1中删除。 - fydelio

9

有另外两个选项可以实现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 }

8
控制器实例变量?这是将信息传递到模板的常规方式。

3
不使用“flag”,而是使用“@flag”。 - Jesse Wolgamott
你是如何尝试设置变量的?编辑就像Jesse所说的那样。如果不知道你正在做什么的其他内容,我们就只能猜测问题可能是什么了。 - Dave Newton
@Dave,请查看更新后的示例。我只想从控制器传递一个变量(flag)到布局中。 - Andrew
1
我认为你不能像那样将本地变量传递给布局;layout只有:only:except选项(至少我知道的是这样)。不知道条件的性质,很难给出通用建议——可能有更好的方法。 - Dave Newton
2
如果有多个要传递的变量,将它们捆绑在哈希或对象中可能很方便,并且可以在需要该布局的所有方法中重复使用。 - mahemoff

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接