Ruby-on-rails 过滤器在渲染之前但在控制器之后执行?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9281224/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 02:49:14  来源:igfitidea点击:

Filter to execute before render but after controller?

ruby-on-railsrubyruby-on-rails-3

提问by Chris

Suppose I have some logic in a base controller to pass information to the view to build something like a breadcrumb:

假设我在基本控制器中有一些逻辑来将信息传递给视图以构建类似面包屑的东西:

class ContextAwareController < ApplicationController

  after_filter :build_breadcrumb

  def build_breadcumb
    #...
  end
end

I want this build_breadcrumb method to run afterthe main controller logic, but beforethe view is rendered.

我希望这个 build_breadcrumb 方法在主控制器逻辑之后运行,但呈现视图之前

The above code runs too late, but a before_filter would be too early.

上面的代码运行得太晚了,但是 before_filter 太早了。

Can anybody suggest a way to accomplish this without explicitly calling build_breadcumb at the end of each of the actions in the child controllers?

任何人都可以建议一种方法来完成此操作,而无需在子控制器中的每个操作结束时显式调用 build_breadcumb 吗?

Thanks

谢谢

采纳答案by Peter Ehrlich

I believe rendering starts when render is called, and there's no default way to defer it. Here's one thing you could do:

我相信渲染在调用渲染时开始,并且没有默认的方法来推迟它。你可以做一件事:

filters are applied in the same order declared. So make a second after-filter that calls render with an array args stored in a class variable. Then anywhere you would normally call render, set the variable.

过滤器以声明的相同顺序应用。因此,使用存储在类变量中的数组 args 调用渲染的第二个后过滤器。然后在您通常调用渲染的任何地方设置变量。

回答by Joshua Muheim

I had the same problem and solved it like this:

我遇到了同样的问题并像这样解决了它:

class ApplicationController < ActionController::Base
  def render *args
    add_breadcrumbs
    super
  end
end

回答by knarewski

There are also some gems to achieve this. One of them is rails3_before_render. It works similarly to filters, for example:

也有一些宝石可以实现这一点。其中之一是rails3_before_render。它的工作原理类似于过滤器,例如:

class PostsController < ApplicationController
  before_render :ping, :except => [:destroy]

  def index; end
  def new; end
  def show; end
  def destroy; end                                                                          

  private
    def ping
      Rails.logger.info "Ping-Pong actions"
    end
end

(code snipped copied from gem documentation)

(从 gem 文档中截取的代码)

回答by Isaac Freeman

If we're overriding render, we're not really using the filter chain at all, so it might be simpler to determine which action we're in using the @_action_name.

如果我们覆盖render,我们根本就没有真正使用过滤器链,因此确定我们正在使用@_action_name.

StuffController < ApplicationController

  def my_filter
    # Do the stuff
  end

  def render(*args)
    my_filter if @_action_name == "show"
    super
  end

end

回答by Lasse Skindstad Ebert

You can do like this to fake a before_render:

您可以这样做来伪造 before_render:

class StuffController < ApplicationController
  before_filter :my_filter, only: [:index, :show]

  def my_filter
    @my_filter = true
  end
  def _my_filter
    # Do the actual stuff here
  end
  def render(*args)
    _my_filter if @my_filter
    super
  end
end

Thanks to @joshua-muheim for the tip about using render

感谢 @joshua-muheim 关于使用的提示 render