rails如何实现before_filter?

Han*_*nXu 20 ruby ruby-on-rails

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

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

我注意到rails的框架维护了一个filter_chain,并在目标方法之前运行过滤器.

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

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

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

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

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

dee*_*our 22

当您设置一个before_filter,或任何类似的过滤器(想想after_filter,around_filter),你用或者是这样的符号PROC,拉姆达或块.

before_filter :bark
before_filter Proc.new { |k| k.bark }
Run Code Online (Sandbox Code Playgroud)

上述追加符号或块的堆叠这里,通过调用set_callback.这构建了您所指的"链".

此"链"中的每个项目都是ActiveSupport::Callbacks::Callback该类的实例.这堂课知道

  • 它必须运行的方法(符号)或块(即你的类' :bark方法)
  • 必须在其中运行的上下文(即您的Dog班级)

Callback实例被附加到一个ActiveSupport::Callbacks::CallbackChain__update_callbacks.

当每个Callback类进行初始化,_compile_filter运行以从所述过滤器正常化Symbol,Proc,λ,或块分割成一个共同的,可调用的格式.

最后,当CallbackChain运行时,它将调用start每个Callback实例,此时它将在适当的上下文中实际执行过滤器.


重要的是要指出你不会创建像这样的过滤器

before_filter dog.bark
Run Code Online (Sandbox Code Playgroud)

这将执行dog.bark并传递它的返回值以before_filter附加到CallbackChain.目的是before_filter为Rails 传递某种指令,以便稍后为您执行.你会做类似的事情

before_filter Proc.new { d = Dog.new; d.bark }
Run Code Online (Sandbox Code Playgroud)

其中的代码Proc未执行.当上面的行由Rails运行时.相反,Rails被告知要传递ProcCallbackChain.这Proc是您传递给Rails以在适当时间执行的"指令".


铁轨如何知道我曾经称之为:树皮

至于这个,假设你的Dog课程被简单定义为

class Dog
  def bark

  end

  def eat

  end
end
Run Code Online (Sandbox Code Playgroud)

(虽然这是一个可怕的例子),你可能想要有类似的东西

before_bark :eat
Run Code Online (Sandbox Code Playgroud)

这需要您定义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
Run Code Online (Sandbox Code Playgroud)

你可以看到这ActiveRecord::Callbacks是怎么回事.

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