inossidabile/protector-cancan

View on GitHub
lib/protector/cancan/ability.rb

Summary

Maintainability
B
6 hrs
Test Coverage
require 'set'

module Protector
  module CanCan
    module Ability

      def import_protector(subject)
        @protector_subject = subject
        @protector_subject_defined = true
      end

      def protector_subject
        @protector_subject
      end

      def protector_subject?
        !!@protector_subject_defined
      end

      def self.included(mod)
        mod.class_eval do

          def can_with_protector?(action, entity_set, *extra_args)
            if entity_set.is_a? Hash
              entity = entity_set.values.first
            else
              entity = entity_set
            end

            if entity.respond_to?(:restrict!) && @protector_subject_defined
              @protector_models ||= Set.new

              model = entity
              model = model.class unless model.is_a?(Class)

              unless @protector_models.include?(model)
                meta = entity.is_a?(Class) ? entity.protector_meta.evaluate(@protector_subject)
                                           : entity.protector_meta(@protector_subject)

                meta.access.each do |action, fields|
                  action = :read if action == :view # *doh*
                  can action, model unless fields.empty?
                end

                can :destroy, model if meta.destroyable?

                @protector_models << model
              end
            end

            can_without_protector? action, entity_set, *extra_args
          end

          alias_method_chain :can?, :protector
        end
      end
    end
  end
end