🥫
【Rails】CanCanCanで現在のユーザに紐づいているレコードのみアクセスOKにしたときcreateが権限なしになる
概要
Rails で、ユーザーへの権限付与に便利な CanCanCan という gem を使っていて、
現在のユーザーに紐づいているレコードだけアクセスOK
という権限にしていたところ、create
ができなくなった。
原因は、新規レコードなのでuser_idがnilになっていた
ことです。
結論
can %i[read update], Article, user_id: user.id
can :create, Article do |article|
article.new_record?
end
より簡潔な書き方
rubocop に注意されたので、そちらに対応した書き方も記載しておきます
can %i[read update], Article, user_id: user.id
can :create, &:new_record? # 変更
試行錯誤の履歴
エラーが出た時の設定
can %i[read update create], Article, user_id: user.id
現在のユーザーに紐づいているレコードだけアクセスOK
という権限にしていたところ、create
ができなくなった。
原因は、新規レコードなのでuser_idがnilになっていた
ことです。
上記理由で動きませんでした。
条件を動きそうなものに置き換えた
can %i[read update create], Article do |article|
article.new_record? || article.user_id == user.id
end
にしたところ、index
にアクセスした際に
The accessible_by call cannot be used with a block 'can' definition.The SQL cannot be determined for :read Article...
となり失敗。
これは、index(設定では read)ではArticle do ~ end
の条件が使えないことが理由のようです
参考:https://stackoverflow.com/questions/26904542/cancan-and-using-has-many-relationships-for-create
解決法(再掲)
can %i[read update], Article, user_id: user.id
can :create, Article do |article|
article.new_record?
end
user_id が空でも OK なのは新規レコード作成の場合だけだったので、create とその他の設定を分けることで解決しました。
Discussion
以下の実装ですが、
RuboCopの警告が出ない正しい実装は以下ではないでしょうか?