2021年12月7日
プログラミング
gem cancancanを使ってみた!


はじめに
この記事は新しい技術にチャレンジし続けるpalanのアドベントカレンダーDay7の記事です!
昨日は「RealityConposerのオブジェクトトラッキングでスノードームを作ってみる!」についての記事でした。
今回は権限管理を行うときに便利なgem cancancanを使ってみました!
今回使用する環境
- Ruby: 2.7.4
- Ruby on Rails: 6.1.4
- cancancan: 3.3.0
事前準備
今回はadmin_usersテーブルにinteger型でroleを追加します
t.integer :role, null: false, default: 0
admin_user.rb
enum role: { editor: 0, sales: 1, system_admin: 99 }
cancancan の導入
Gemfile
gem 'cancancan'
$ bundle install を実行
権限の設定
Ability クラスの作成
app/models/ability.rbを作成
$ rails generate cancan:ability
Ability クラスの設定
class Ability
include CanCan::Ability
def initialize(admin_user)
#基本的には権限をモデルごとに設定する
if admin_user.system_admin?
can :manage, :all
# 全てのコントローラーで全てのアクションが実行できる
elsif admin_user.editor?
can :manage, Article
cannot :destroy, Article
# Articleのdestroyを除く全てのアクションが実行できる
elsif admin_user.sales?
can :read, Company
# Companyの読み取り(index, show)だけができる
end
end
end
設定できるアクション
manageの他に以下4つのエイリアスが存在します。
ちなみにmanageには以下の基本のCRUD以外にも自分で追加したsearchアクションなども含まれるので注意しましょう!
POINT!!
read: [:index, :show]
create: [:new, :create]
update: [:edit, :update]
destroy: [:destroy]
権限設定の利用
load_and_authorize_resourceメソッドを利用すると、自動的にリソースの取得と権限チェックを行ってくれます。
article_controller.rb
class ArticlesController < ApplicationController
load_and_authorize_resource
def index
# 読み取り可能な@articlesが読み込まれている
end
def show
# @articleが読み込まれて権限もチェックされている
end
def create
# @articleが読み込まれてarticle_paramsがセットされ、権限もチェックされている
@article.create
end
def edit
# @articleが読み込まれて権限もチェックされている
end
def update
# @articleが読み込まれて権限もチェックされている
@article.update(article_params)
end
def destroy
# @articleが読み込まれて権限もチェックされている
@article.destroy
end
private
def article_params
params.require(:article).permit(:body)
end
end
AccessDeniedの制御
権限がない際に時に発生するCanCan::AccessDenied exceptionをApplicationControllerで制御します。
application_controller.rb
class ApplicationController < ActionController::Base
# 権限が無いページへアクセス時の例外処理
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_path, flash: { danger: '権限がありません' }
end
操作可能なリソースの条件設定
ユーザーがオーナーの記事だけ読み書き削除できるようにしたい
Article.rb
belongs_to :owner, class_name: 'AdminUser', foreign_key: :admin_user_id
Ability.rb
can manage, Aeticle, owner: admin_user
ユーザーがCompanyに紐づくいずれかのOrderの営業担当の時だけCompanyの読み取りをできるようにしたい
Company.rb
scope :orders_in_charge_of_sales, ->(admin_user) { where(id: Order.where(sales_person: admin_user).pluck(:company_id)) }
Order.rb
belongs_to :company
belongs_to :sales_person, class_name: 'AdminUser'
Ability.rb
can :read, Company, Company.orders_in_charge_of_sales(admin_user) do |record|
# レコードの権限判定
record.orders.any? { |order| order.sales_person == admin_user }
end
ハッシュでは表現できない複雑な条件を指定するときはブロックを利用します。
indexアクションでアクセス可能な全リソースを取得するときのためにスコープを渡し、ブロック内では個別のレコードの権限判定を記述します。
更に詳しくはcancancan のWiki 「Define abilities with blocks」の項目 をご覧ください。
まとめ
cancncanはとても便利なのですが、最初はハッシュで表現できない条件などの設定に少し苦労しました。この記事が何かのお役に立てれば幸いです!
Rubyのお仕事に関するご相談
Bageleeの運営会社、palanではRubyに関するお仕事のご相談を無料で承っております。
zoomなどのオンラインミーティング、お電話、貴社への訪問、いずれも可能です。
ぜひお気軽にご相談ください。
この記事は
参考になりましたか?
0
0
関連記事

2021年12月22日
RDBでセットメニューを表現する方法

2021年12月11日
Railsでツリー構造アプリを作ってみた

2021年12月9日
モデルに書いていたメソッドをPOROに切り出してみた!

2021年12月7日
gem cancancanを使ってみた!

2021年11月15日
CustomCopで命名規則を作ってみた

2021年10月29日
clambyを利用したウイルススキャン
簡単に自分で作れるWebAR
「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。
palanARへ








