Skip to content

Instantly share code, notes, and snippets.

@dalezak
Last active February 23, 2022 11:31
Show Gist options
  • Save dalezak/ab763b41f2fb086c39ef42018879f31e to your computer and use it in GitHub Desktop.
Save dalezak/ab763b41f2fb086c39ef42018879f31e to your computer and use it in GitHub Desktop.
Lazy Load CanCanCan Abilities In Rails
def current_ability
@current_ability ||= begin
current_ability = Ability.new(current_user)
controller_names.to_a.each do |controller_name|
model_name = controller_name.classify
model_ability = "#{model_name}Ability".constantize rescue nil
if model_ability.present? && model_abilities[model_ability].nil?
model_abilities[model_ability] = model_ability.new(current_user)
current_ability.merge(model_abilities[model_ability])
end
end
current_ability
end
end
def can?(*args)
merge_ability(args[1])
current_ability.can?(*args)
end
def cannot?(*args)
merge_ability(args[1])
current_ability.cannot?(*args)
end
def authorize!(*args)
merge_ability(args[1])
current_ability.authorize!(*args)
end
def model_abilities
@model_abilities ||= {}
end
def controller_names
@controller_names ||= begin
regex_digit = /\d/
regex_uuid = /[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}/
controller_names = request.path.split("/")
controller_names = controller_names.reject { |p| p.match?(regex_uuid) || p.match?(regex_digit) || p.empty? }
controller_names = controller_names.map{ |p| File.basename(p, File.extname(p))}
if controller_names.include?(controller_name)
controller_names = controller_names.take(controller_names.index(controller_name)+1)
end
end
end
def merge_abilities(*model_names)
model_names.each do |model_name|
merge_ability(model_name.to_s)
end
end
def merge_ability(model)
model_name = model.is_a?(Class) ? model.name : model.class.name
model_ability = "#{model_name}Ability".constantize rescue nil
if model_ability.present? && model_abilities[model_ability].nil?
model_abilities[model_ability] = model_ability
current_ability.merge(model_ability.new(current_user))
end
end
class ModelAbility
include CanCan::Ability
def initialize(user)
if user.nil?
self.user(user)
elsif user.is_a?(Admin)
self.admin(user)
end
end
def admin(user)
end
def user(user)
end
end
class PostAbility < ModelAbility
def admin(user)
can :manage, Post
end
def user(user)
can :create, Post
can :read, Post
can :update, Post, user_id: user.id
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment