Last active
June 11, 2021 11:31
-
-
Save chriscz/ac35172e0870248af16b23475a7ddb72 to your computer and use it in GitHub Desktop.
Add ActiveRecord::Relation support to CanCan can? check
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'cancancan_ability_ext' | |
class Ability | |
include CanCan::Ability | |
include CanCanCanAbilityExt | |
def initialize(user) | |
can :clone, Post, { id: user.post_ids } | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This module extends cancan abilities to work with ActiveRecord relations when used with +authorize!+ or | |
# +ability.can?+. | |
# | |
# The extension is bypassed if attribute or extra_args are defined. | |
module CanCanCanAbilityExt | |
def can?(action, subject, attribute = nil, *extra_args) | |
if attribute.nil? && extra_args.blank? | |
if subject.is_a?(ActiveRecord::Relation) | |
return can_collection?(action, subject.klass, subject) | |
end | |
end | |
super(action, subject, attribute, *extra_args) | |
end | |
private | |
def can_collection?(action, klass, unchecked_records) | |
accessible_records = klass.accessible_by(self, action).merge(unchecked_records) | |
accessible_records.count == unchecked_records.count | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PostsController < ApplicationController | |
def index | |
@posts = Post.accessible_by(current_ability) | |
end | |
def bulk_clone | |
# We want to raise an AccessDenied instead of using accessible_by here because we would rather let the user | |
# know they have an invalid post_id in their params than fulfilling the request on a subset of the post_ids. | |
@posts = Post.find(params[:post_ids]) | |
authorize!(:clone, @posts) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment