LoginSignup
3
1

More than 5 years have passed since last update.

BtoBアプリケーションの権限設定

Last updated at Posted at 2018-03-04

目的は権限設定なのですが、内容はcurrent_userをmodelで使う方法になっております。。

背景

Rails+deviseで稼働中のAPIで、ユーザー毎の権限設定を追加したい。
いわゆるSaasで業務システムを開発しています。権限設定もいろいろなパターンがあると思うんですが、今回はデータに触れることが出来るかどうかを制御するパターンです(参照・更新できるかどうかではない)

実装検討

権限設定には大きく分けて2種類ある。。と思う。
1. 機能を制御(主にcontrollerで制御する。参照・更新・削除できるかどうか。)
2. データを制御(modelで制御? あるデータを扱えるかどうか。)

1はイメージしやすい。各APIを使う権限であり、controllerのメソッドを制御できれば良く、cancancan、pundit等のgemがある。
2は主に対象データのあるレコードが参照可能か、更新可能かを制御する。
例えば、ユーザーAは、itemモデルのid:1のデータを更新可で、id:2のデータは参照不可。ユーザーBはid:2だけ更新可のような。

2のようなデータ制御ができるgemを自分は知らない。そこで、current_userをmodelのdefault_scopeで使ってしまうことにした。
本当はcontrollerでできると思うが、controller数もかなり多いので。。

Thread.currentを使う

以下の様に書くと、modelでUser.current_idが使えるようになる。
User.current_id = nil で処理後にクリアしているので、これでも上手く動いていた。

def current_id=(id)
  Thread.current[:user_id] = id
end

def current_id
  Thread.current[:user_id]
end

around_action :scope_current_user

  private

  def scope_current_user
    User.current_id = current_user.id
    yield
  ensure
    User.current_id = nil
  end

request_storeを使う

上記のThread.currentでもできるが、request_storeというgemを使うと、rack層でクリアしてくれる。

authenticated_controller.rbを以下のように変更する。
すると、RequestStore.store[:current_user_id] がmodelで使えるようになる。

  around_action :scope_current_user

  private

  def scope_current_user
    RequestStore.store[:current_user_id] = current_user.id
    yield
  end

以上で、modelでcurrent_user.idが使えるようになった。 current_user.idでユーザー毎に設定された権限を取得し、default_scopeに条件を追加する。これで、データを制御する権限設定が比較的かんたんに実現できる。
※ default_scopeは本来は使いたくないですね。

他に良い方法があればコメント下さい!!

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1