[Rails 5]モジュールやクラスレベルの変数をスレッドベースで作成する機能(翻訳)

こんにちは、hachi8833です。BigBinaryシリーズの本日2本目をお送りします。

本機能のRails 5.1での修正点については「[Rails 5.1]thread_mattr_accessorの変数はサブクラスと共有されないようになった(翻訳)」をご覧ください。

概要

モジュールやクラスレベルの変数をスレッドベースで作成する機能(翻訳)

Railsでは以前から、cattr_readercattr_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_permissionsRequestScope.user_permissionsでアクセスできます。

従来PerThreadRegistryでグローバル変数を管理していた場合は、Rails 5からthread_mattr_*thread_cattr_*に置き換えられます。

グローバル変数は一般に悪影響をもたらすため、今後はこのような改良APIを利用しましょう。

訳注: PerThreadRegistryは現在非推奨になっています。

関連記事

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ