Ruby on rails の権限管理ライブラリの中で一番ダウンロード数が多いGemであるcancancanのv3.0が2019年4月にリリースされました。
仕事のプロジェクトで使っているcancancanのバージョンは随分前にv3.0に上げていたのですが、結構大きな変更が入っていることを認識できていなかったことに最近気が付き、これからアップグレードをする方や新規にCancancanを導入する方に向けて、どんなところに注意したら良いのかをまとめてみることにしました。
注意点を認識していないと、気がつかない間に
- N+1(パフォーマンス問題)が発生する
- SQLクエリ実行時にエラーが発生する
といった問題が発生する可能性があります。
Cancancan公式のドキュメントのURLも載せておきます。
GitHub - CanCanCommunity/cancancan: The authorization Gem for Ruby on Rails.
4つの注意点(Breaking changes)
注意点(Breaking changes)は4点ありますが、特に2番目、3番目を意識すると問題の発生を避けられそうです。
①権限を定義するアビリティにSubjectを定義しなくてはいけなくなった
例えば、ダッシュボードに対する権限を指定する場合
can :dashboard
のように書くことができなくなりました。具体的に
can :read, :dashboard
のように、ダッシュボードのリード権限があるという書き方をする必要があります。
- 以前よりDefining AbilitiesのWikiページ で、後者の書き方が載っていたので、あまり前者の書き方をしているプロジェクトはない
- 前者の書き方をしているとエラーが発生するようになった
ため、この注意点に関してはあまり意識しておかなくても問題ないと思います。
しかし
- 権限のテストをあまり書いていないプロジェクト
- アップグレード後に手動でも動作確認をしていない
場合だと、気がつかずにプロダクションに反映する恐れがあるので注意が必要になりそうです。
②Eager loadingを自動的に行わなくなった。
具体的には、このPRの差分になるのですが、今まではモデルに :has_many
などで紐付いているモデルは includes
して読み込んでいたのですが、left_joins
に変わったのでN+1が発生する可能性がでてきました。
具体的には、Book(本)モデルの :has_many
にAuthor(著者)モデルがあるような場合で、書籍一覧(Booksのindexページ)で、著者名(author.name)を表示するようなケースが該当します。
なので
- N+1を検知するbullet gemを導入 (公式でも推奨されている)
- 一覧画面で、N+1が発生し得る箇所で関連モデルを
includes
する
といった対応を行った方が良さそうです。
③Distinctを使うようになった
②と同じ差分で、クエリでdistinctを行うようになったことがわかります。
例えば、load_resource
を読み込んだ結果(ActiveRecord::Relation)に対してorder
やgroup by
を付けて以下のようなクエリになっていた場合は、PostgreSQLの場合クエリ実行時にエラーになります。
SELECT DISTINCT users.id FROM users order by users.email => ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
このような場合、selectの値を見直し、users.emailを含めるようにするといった対応が必要になります。
④アビリティファイルをマージした際、エイリアスもマージされるようになった
権限が複雑になってくるとアビリティファイルを分けたり、それらのアビリティをマージしたくなってきます。
cancancanのアビリティには、mergeというメソッドが定義されていて以前からマージを行うことができるようになっていましたが、エイリアスはマージされないといった問題があったようです。
- https://github.com/CanCanCommunity/cancancan/issues/468
- https://github.com/CanCanCommunity/cancancan/issues/280
cancancan 3.0でエイリアスもマージできるようになったようですが、Railsプロジェクトはそこまで複雑になる案件には向かないと思うので
- アビリティのマージをしている
- エイリアスも使っている
というのはあまり多くはなさそう。ということでこの4点目は比較的重要度は低そうです。