TheRole/TheRoleApi

View on GitHub
app/models/concerns/the_role/api/role.rb

Summary

Maintainability
A
25 mins
Test Coverage
module TheRole
  module Api
    module Role
      extend ActiveSupport::Concern

      include TheRole::Api::BaseMethods

      # HELPERS

      # version for `Role` model
      def role_hash
        to_hash
      end

      def the_role= val
        self[:the_role] = _jsonable val
      end

      def _jsonable val
        val.is_a?(Hash) ? val.to_json : val.to_s
      end

      def to_hash
        begin JSON.load(the_role) rescue {} end
      end

      def to_json
        the_role
      end

      # ~ HELPERS

      alias_method :has?, :has_role?
      alias_method :any?, :any_role?

      def has_section? section_name
        to_hash.key? section_name.to_slug_param(sep: '_')
      end

      included do
        attr_accessor :based_on_role

        has_many  :users, dependent: TheRole.config.destroy_strategy
        validates :name,  presence: true, uniqueness: true
        validates :title, presence: true, uniqueness: true
        validates :description, presence: true

        private

        before_save do
          self.name = name.to_slug_param(sep: '_')

          rules_set     = self.the_role
          self.the_role = {}.to_json        if rules_set.blank?
          self.the_role = rules_set.to_json if rules_set.is_a?(Hash)
        end

        after_create do
          if based_on_role.present?
            if base_role = self.class.where(id: based_on_role).first
              update_role base_role.to_hash
            end
          end
        end
      end

      module ClassMethods
        def with_name name
          ::Role.where(name: name).first
        end
      end

      # C

      def create_section section_name = nil
        return false unless section_name

        role         = to_hash
        section_name = section_name.to_slug_param(sep: '_')

        return false if section_name.blank?
        return true  if role[section_name]

        role[section_name] = {}
        update_attribute(:the_role, _jsonable(role))
      end

      def create_rule section_name, rule_name
        return false if     rule_name.blank?
        return false unless create_section(section_name)

        role         = to_hash
        rule_name    = rule_name.to_slug_param(sep: '_')
        section_name = section_name.to_slug_param(sep: '_')

        return true if role[section_name][rule_name]

        role[section_name][rule_name] = false
        update_attribute(:the_role,  _jsonable(role))
      end

      # U

      # source_hash will be reset to false
      # except true items from new_role_hash
      # all keys will become 'strings'
      # look at lib/the_role/hash.rb to find definition of *underscorify_keys* method
      def update_role new_role_hash
        new_role_hash = new_role_hash.try(:to_hash) || {}

        new_role = new_role_hash.underscorify_keys
        role     = to_hash.underscorify_keys.deep_reset(false)

        role.deep_merge! new_role
        update_attribute(:the_role,  _jsonable(role))
      end

      def rule_on section_name, rule_name
        role         = to_hash
        rule_name    = rule_name.to_slug_param(sep: '_')
        section_name = section_name.to_slug_param(sep: '_')

        return false unless role[section_name]
        return false unless role[section_name].key? rule_name
        return true  if     role[section_name][rule_name]

        role[section_name][rule_name] = true
        update_attribute(:the_role,  _jsonable(role))
      end

      def rule_off section_name, rule_name
        role         = to_hash
        rule_name    = rule_name.to_slug_param(sep: '_')
        section_name = section_name.to_slug_param(sep: '_')

        return false unless role[section_name]
        return false unless role[section_name].key? rule_name
        return true  unless role[section_name][rule_name]

        role[section_name][rule_name] = false
        update_attribute(:the_role,  _jsonable(role))
      end

      # D

      def delete_section section_name = nil
        return false unless section_name

        role = to_hash
        section_name = section_name.to_slug_param(sep: '_')

        return false if section_name.blank?
        return false unless role[section_name]

        role.delete section_name
        update_attribute(:the_role,  _jsonable(role))
      end

      def delete_rule section_name, rule_name
        role         = to_hash
        rule_name    = rule_name.to_slug_param(sep: '_')
        section_name = section_name.to_slug_param(sep: '_')

        return false unless role[section_name]
        return false unless role[section_name].key? rule_name

        role[section_name].delete rule_name
        update_attribute(:the_role,  _jsonable(role))
      end
    end
  end
end