# frozen_string_literal: true module Monarchy module ActsAsResource extend ActiveSupport::Concern module ClassMethods def acts_as_resource(options = {}) extend Monarchy::ActsAsResource::SupportMethods setup_acting parent_as(options[:parent_as]) if options[:parent_as] after_create :ensure_hierarchy after_save :assign_parent has_many :members, through: :hierarchy, class_name: "::#{Monarchy.member_class}" has_many :users, through: :members, class_name: "::#{Monarchy.user_class}" has_one :hierarchy, as: :resource, dependent: :destroy, class_name: 'Monarchy::Hierarchy' include_scopes include Monarchy::ActsAsResource::InstanceMethods end end module SupportMethods attr_accessor :parentize, :acting_as_resource private def setup_acting Monarchy.resource_classes << self @acting_as_resource = true end def parent_as(name) self.parentize = name end def include_scopes scope :in, (lambda do |resource| joins(:hierarchy).where(monarchy_hierarchies: { parent_id: resource.hierarchy.self_and_descendants }) end) scope :accessible_for, (lambda do |user| joins(:hierarchy).where(monarchy_hierarchies: { id: Monarchy::Hierarchy.accessible_for(user) }) end) end end module InstanceMethods def parent @parent = hierarchy.try(:parent).try(:resource) || @parent end def parent=(resource) if hierarchy hierarchy.update(parent: resource.try(:hierarchy)) else @parent = resource end end def children @children ||= children_resources end def children=(array) hierarchy.update(children: hierarchies_for(array)) if hierarchy @children = array end private def ensure_hierarchy self.hierarchy ||= Monarchy::Hierarchy.create( resource: self, parent: parent.try(:hierarchy), children: hierarchies_for(children) ) end def assign_parent(force = false) parent = self.class.parentize if parent was_changed = changes["#{parent}_id"] || changes["#{parent}_type"] self.parent = send(parent) if was_changed || force end end def children_resources c = hierarchy.try(:children) return nil if c.nil? c.includes(:resource).map(&:resource) end def hierarchies_for(array) Array(array).map(&:hierarchy) end end end end ActiveRecord::Base.send :include, Monarchy::ActsAsResource