- 開発
READ MORE
こんにちは、hachi8833です。BigBinaryシリーズの本日2本目をお送りします。
本機能のRails 5.1での修正点については「[Rails 5.1]thread_mattr_accessorの変数はサブクラスと共有されないようになった(翻訳)」をご覧ください。
Railsでは以前から、cattr_reader
、cattr_writer
、cattr_accessor`という一連のメソッドを使ってクラスレベルの変数やモジュールレベルの変数を作成する機能が提供されていました。
Rails 5ではこれをさらに押し進め、クラスレベルの変数やモジュールレベルの変数をスレッド固有の形で作成できるようになりました。
以下の例をご覧ください。
module CurrentScope
thread_mattr_accessor :user_permissions
end
class ApplicationController < ActionController::Base
before_action :set_permissions
def set_permissions
user = User.find(params[:user_id])
CurrentScope.user_permissions = user.permissions
end
end
このCurrentScope.user_permissions
は、実行中のスレッドが完了するまでアクセスできるので、このコード以降で変数にアクセスできます。
これを利用して、たとえばコントローラで明示的にcurrent_user
を渡さなくてもすべてのモデルで変数にアクセスできるようになります。
class BookingsController < ApplicationController
def create
Booking.create(booking_params)
end
end
class Booking < ApplicationRecord
validate :check_permissions
private
def check_permissions
unless CurrentScope.user_permissions.include?(:create_booking)
self.errors.add(:base, "Not permitted to allow creation of booking")
end
end
end
内部で使われているThread.current#[]=
メソッドによって、指定したすべての変数のスコープが現在実行中のスレッドに対して設定されます。
作成したクラスやモジュールの変数では名前空間が有効になるため、衝突の心配なしにCurrentScope.user_permissions
やRequestScope.user_permissions
でアクセスできます。
従来PerThreadRegistry
でグローバル変数を管理していた場合は、Rails 5からthread_mattr_*
やthread_cattr_*
に置き換えられます。
グローバル変数は一般に悪影響をもたらすため、今後はこのような改良APIを利用しましょう。
訳注:
PerThreadRegistry
は現在非推奨になっています。