过滤器

过滤器是在控制器操作之前之后周围运行的方法。它们是继承的,因此如果你在 ApplicationController 中设置了它们,它们将针对你的应用程序收到的每个请求运行。

在过滤之前

在控制器操作之前执行过滤器之前,可以暂停请求(和/或重定向)。常见的用途是验证用户是否已登录:

class ApplicationController < ActionController::Base
  before_action :authenticate_user!

  def authenticate_user!
    redirect_to some_path unless user_signed_in?
  end
end

在请求到达控制器的操作之前,在请求上运行过滤器之前。它可以自己返回响应并完全绕过该操作。

过滤器的其他常见用途是在授予用户访问指定处理其请求的操作之前验证用户的身份验证。我还看到它们用于从数据库加载资源,检查资源的权限,或在其他情况下管理重定向。

过滤后

过滤器类似于之前过滤器,但是当它们在动作运行后执行时,它们可以访问即将发送的响应对象。因此,在操作完成后运行过滤器之后。它可以修改响应。大多数情况下,如果在后置过滤器中完成某些操作,可以在操作本身中完成,但如果在运行任何一组操作后有一些逻辑要运行,那么后置过滤器是一个好的做法它。

一般来说,我已经看到用于记录的过滤器后面和周围。

过滤器周围

在运行动作之前和之后,过滤器周围可能有逻辑。它只是在任何必要的地方产生动作。请注意,它不需要屈服于该操作,并且可以在不像过滤器那样的情况下运行。

过滤器负责通过屈服运行相关的操作,类似于 Rack 中间件的工作方式。

回调周围包含了动作的执行。你可以用两种不同的风格来编写回调。在第一个中,回调是一个代码块。在执行操作之前调用该代码。如果回调代码调用 yield,则执行该操作。操作完成后,回调代码将继续执行。因此,yield 之前的代码就像 before action 回调,yield 之后的代码就是 after action 回调。如果回调代码从不调用 yield。该操作未运行 - 这与之前的操作回调返回 false 相同。

以下是 around 过滤器的示例:

around_filter :catch_exceptions
 
private
  def catch_exceptions
    begin
      yield
    rescue Exception => e 
      logger.debug "Caught exception! #{e.message}"
    end
  end

这将捕获任何操作的异常并将消息放入你的日志中。你可以在周围使用过滤器进行异常处理,设置和拆卸以及无数其他情况。

只有和除外

使用:only:except 可以将所有过滤器应用于特定操作:

class ProductsController < ApplicationController
  before_action :set_product, only: [:show, :edit, :update]

  # ... controller actions

  # Define your filters as controller private methods
  private

  def set_product
    @product = Product.find(params[:id])
  end
end

跳过过滤器

对于某些特定操作,也可以跳过所有过滤器(也是继承的过滤器):

class ApplicationController < ActionController::Base
  before_action :authenticate_user!

  def authenticate_user!
    redirect_to some_path unless user_signed_in?
  end
end

class HomeController < ApplicationController
  skip_before_action :authenticate_user!, only: [:index]

  def index
  end
end

由于它们是继承的,因此也可以在 namespace控制器中定义过滤器。比如说你有一个 admin 命名空间,当然你只希望管理员用户能够访问它。你可以这样做:

# config/routes.rb
namespace :admin do
  resources :products
end

# app/controllers/admin_controller.rb
class AdminController < ApplicationController
  before_action :authenticate_admin_user!

  private

  def authenticate_admin_user!
    redirect_to root_path unless current_user.admin?
  end
end

# app/controllers/admin/products_controller.rb
class Admin::ProductsController < AdminController
  # This controller will inherit :authenticate_admin_user! filter
end

请注意,在 Rails 4.x 中你可以使用 before_filterbefore_action,但 before_filter 目前在 Rails 5.0.0 中已被弃用,并将在 5.1 中删除。