【问题标题】:Rails set layout from within a before_filter methodRails 在 before_filter 方法中设置布局
【发布时间】:2011-07-12 23:22:05
【问题描述】:

是否可以在 Rails 3 的 before_filter 方法中重置默认布局?

我的 contacts_controller.rb 有以下内容:

class ContactsController < ApplicationController
  before_filter :admin_required, :only => [:index, :show]
  def show
    @contact = Contact.find(params[:id])
    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @contact }
    end
  end
  [...]
end

以及我的 application_controller.rb

中的以下内容
class ApplicationController < ActionController::Base
  layout 'usual_layout'
  private
  def admin_required
    if !authorized?          # please, ignore it. this is not important
      redirect_to[...]
      return false
    else
      layout 'admin'  [???]  # this is where I would like to define a new layout
      return true
    end
  end
end

我知道我可以放...

layout 'admin', :only => [:index, :show]

...在“ContactsController”中的“before_filter”之后,但是,由于我已经有一堆其他控制器,其中许多操作被正确过滤为管理员所需的操作,如果我可以重置会容易得多在“admin_required”方法中从“usual_layout”到“admin”的布局。

顺便说一句,通过放...

layout 'admin'

...在“admin_required”内(正如我在上面的代码中所尝试的那样),我收到一条未定义的方法错误消息。它似乎只在 defs 之外工作,就像我为“usual_layout”所做的那样。

提前致谢。

【问题讨论】:

    标签: ruby-on-rails layout before-filter


    【解决方案1】:

    来自Rails guides2.2.13.2 Choosing Layouts at Runtime

    class ProductsController < ApplicationController
      layout :products_layout
    
      private
    
      def products_layout
        @current_user.special? ? "special" : "products"
      end
    end
    

    【讨论】:

    • 感谢 apneadiving,但这并不是我的意思。我已经在一堆控制器上正确地预先执行了一个方法,过滤了应该使用这种特殊布局呈现的相同操作。但是这个方法是由 before_filter 命令触发的。我不想用现在指向内部方法的布局命令替换每个控制器上的每个 before_filter,我会得到正确的布局名称 - 或者无论如何添加它。我需要在 before_filter 命令已经触发的相同方法中定义特殊布局。
    • 好吧,我决定听从 apneadiving 的建议。我花了一段时间,但我用'layout:admin_required,:only => [...]'替换了每个'before_filter:admin_required,:only => [...]'。它工作得很好。谢谢。
    • 谁能解释一下这条线是什么意思? @current_user.special? ? "special" : "products" 谢谢!!
    • @Lucas 它是一个三元运算符
    【解决方案2】:

    如果由于某种原因您无法修改现有控制器和/或只想在前置过滤器中执行此操作,您可以使用self.class.layout :special 这是一个示例:

    class ProductsController < ApplicationController
      layout :products
      before_filter :set_special_layout
    
      private
    
      def set_special_layout
        self.class.layout :special if @current_user.special?
      end
    end
    

    这只是做同样重要事情的另一种方式。更多的选择让程序员更快乐!!

    【讨论】:

    • 我在使用这种方法时遇到的最大问题是布局被 Rails 缓存,因此即使在不应该的情况下也可以应用。线程安全之类的。使用layout :set_layoutdef set_layout 方式,更安全:)
    【解决方案3】:

    现代的做法是使用 proc,

    layout proc { |controller| user.logged_in? "layout1" : "layout2" }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-02
      • 2011-01-24
      • 1970-01-01
      • 2013-10-22
      相关资源
      最近更新 更多