module ActsAsBelongable module Belonger extend ActiveSupport::Concern module ClassMethods def acts_as_belonger has_many :belongables, through: :belonger_belongings, source: :belongable has_many :belonger_belongings, as: :belonger, class_name: 'Belonging', dependent: :destroy end def belonger name, source_type, options = {} if options.has_key? :scope belonger_belongings_with_scope options[:scope] through = "belonger_belongings_#{options[:scope]}".to_sym end through ||= :belonger_belongings has_many name.to_sym, through: through, source: :belongable, source_type: source_type.to_s end def belonger_belongings_with_scope scope has_many "belonger_belongings_#{scope}".to_sym, -> { where(scope: scope.to_s) }, as: :belonger, class_name: 'Belonging', dependent: :destroy end end def add_belongable belongable, options = {} options[:belongable] = belongable self.belonger_belongings.create options end def add_belongable! belongable, options = {} options[:belongable] = belongable self.belonger_belongings.create! options end def create_belongable class_name, options = {} belonging_options = options.delete :belonging object = class_name.constantize.create options self.add_belongable object, belonging_options object end def create_belongable! class_name, options = {} belonging_options = options.delete :belonging object = class_name.constantize.create! options self.add_belongable! object, belonging_options object end def belongables_with_scope scope, source_type = nil self.belonger_belongings.where(scope: scope.to_s).map { |belonging| source_type.nil? || belonging.belongable.class.name == source_type ? belonging.belongable : nil }.compact end end end