rails如何实现before_filter?

时间:2012-08-29 09:25:42

标签: ruby-on-rails ruby

我对rails如何实现before_filter等过滤器感兴趣。

但在阅读完源代码后,我仍然感到困惑。

我注意到rails'框架维护filter_chain,并在目标方法之前运行过滤器。

但是,我不明白一个重要的过程:rails如何捕获一个方法调用?

我的意思是,例如,我有一个班级Dog,并为方法树皮设置before_filter

当我调用dog.bark时,rails应该以某种方式捕获此调用,并改为运行其修改后的方法。

但是,我在源代码中找不到这样的代码。

任何人都可以告诉我这个想法或指出代码所在的位置吗?

2 个答案:

答案 0 :(得分:22)

当您设置before_filter或任何类似的过滤器(想想after_filteraround_filter时,您正在使用{{3}进行设置}或Symbol,lambda或块。

before_filter :bark
before_filter Proc.new { |k| k.bark }

上面通过调用Proc将符号或块附加到堆栈here。这构建了您所指的“链”。

此“链”中的每个项目都是set_callback类的实例。这堂课知道

  • 方法(符号)或阻止它必须运行(即您的班级“:bark方法”
  • 必须在中运行的上下文(即您的Dog类)

Callback个实例会附加到ActiveSupport::Callbacks::Callback中的ActiveSupport::Callbacks::CallbackChain

初始化每个Callback类时,运行__update_callbacks以将过滤器从SymbolProc,lambda或块规范化为通用的可调用格式。

最后,当CallbackChain运行时,它会在每个Callback实例上调用_compile_filter,并在此时调用 过滤器实际执行在适当的背景下。


重要的是要指出你创建像

这样的过滤器
before_filter dog.bark

这将执行dog.bark并将其返回值传递给before_filter以附加到CallbackChain。目的是将某些指令传递给before_filter以便Rails稍后为您执行。你会做一些像

这样的事情
before_filter Proc.new { d = Dog.new; d.bark }

Proc内的代码未执行。当上面的行由Rails运行时。相反,Rails被告知将Proc传递给CallbackChainProc是您传递给Rails以在适当时间执行的'指令'。


  

首先,铁路如何知道我已经召集过:bark

至于此,假设您的Dog类被简单定义为

class Dog
  def bark

  end

  def eat

  end
end

(虽然这是一个可怕的例子),你可能想要像

这样的东西
before_bark :eat

这需要您定义bark回调,然后告诉您的bark方法运行相关的bark回调。

class Dog
  extend ActiveModel::Callbacks

  define_callbacks :bark

  before_bark :eat

  def bark
    run_callbacks(:bark) { YOUR BARK CODE HERE }
  end

  def eat

  end
end

您可以看到start如何做到这一点。

这确实是一个糟糕的例子,因为你可以(而且应该)直接从eat调用bark,但这应该得到重点。

答案 1 :(得分:1)

Rails不会按照您描述的方式捕获方法调用。如果查看AbstractController::Base.process,它将查找要为调度操作调用的方法,运行过滤器然后调用实际方法。换句话说,您的控制器方法不是直接调用,而是通过此process方法调用。