過濾器

過濾器是在控制器操作之前之後周圍執行的方法。它們是繼承的,因此如果你在 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 中刪除。