使用场景:需要 persist 一些全局数据,如 request 中内容,user 之类
Abstract super class that provides a thread-isolated attributes singleton.
Primary use case is keeping all the per-request attributes easily available to the whole system.
The following full app-like example demonstrates how to use a Current class to facilitate easy access to the global, per-request attributes without passing them deeply around everywhere:
# app/models/current.rb class Current < ActiveSupport::CurrentAttributes attribute :account, :user attribute :request_id, :user_agent, :ip_address resets { Time.zone = nil } def user=(user) super self.account = user.account Time.zone = user.time_zone end end # app/controllers/concerns/authentication.rb module Authentication extend ActiveSupport::Concern included do before_action :set_current_authenticated_user end private def set_current_authenticated_user Current.user = User.find(cookies.signed[:user_id]) end end # app/controllers/concerns/set_current_request_details.rb module SetCurrentRequestDetails extend ActiveSupport::Concern included do before_action do Current.request_id = request.uuid Current.user_agent = request.user_agent Current.ip_address = request.ip end end end class ApplicationController < ActionController::Base include Authentication include SetCurrentRequestDetails end class MessagesController < ApplicationController def create Current.account.messages.create(message_params) end end class Message < ApplicationRecord belongs_to :creator, default: -> { Current.user } after_create { |message| Event.create(record: message) } end class Event < ApplicationRecord before_create do self.request_id = Current.request_id self.user_agent = Current.user_agent self.ip_address = Current.ip_address end end
A word of caution: It's easy to overdo a global singleton like Current and tangle your model as a result. Current should only be used for a few, top-level globals, like account, user, and request details. The attributes stuck in Current should be used by more or less all actions on all requests. If you start sticking controller-specific attributes in there, you're going to create a mess.