Sha256: 1525377f54a8f6bc5a30a2c6b60a0ecf82c106e2633126a68179d10e7275368f

Contents?: true

Size: 1.93 KB

Versions: 1

Compression:

Stored size: 1.93 KB

Contents

# frozen_string_literal: true

module BelongsToPolymorphic
  module Associations
    def self.included(base)
      base.extend ClassMethods
    end

    module ClassMethods
      def belongs_to_polymorphic(name, allowed_classes:, **options)
        allowed_classes = Array.wrap(allowed_classes)
        belongs_to name, polymorphic: true, **options

        validates "#{name}_type", inclusion: {
          in: classes(allowed_classes, options),
          message: I18n.t('belongs_to_polymorphic.errors.messages.class_not_allowed',
                          class: '%<value>s')
        }

        define_singleton_method("#{name}_types") { allowed_classes }
        define_generic_finder_method(name)
        define_scopes_and_instance_methods(name, allowed_classes)
      end

      private

      def classes(allowed_classes, options)
        classes = allowed_classes.map(&:name)
        classes << nil if options[:optional]
        classes
      end

      # Generates a generic finder method
      def define_generic_finder_method(name)
        define_singleton_method("with_#{name}") do |type|
          type = case type
                 when Class then type.name
                 when String then type
                 else type.class.name
                 end
          where("#{name}_type" => type)
        end
      end

      def define_scopes_and_instance_methods(name, allowed_classes)
        allowed_classes.each do |model|
          model_name = model.name
          model_name_sanitized = model_name.underscore.tr('/', '_')
          # generates scope for each allowed class
          scope "with_#{name}_#{model_name_sanitized}",
                -> { where("#{name}_type" => model_name) }

          # generates instance method for each allowed class to check if type is that class
          define_method("#{name}_type_#{model_name_sanitized}?") do
            public_send("#{name}_type") == model_name
          end
        end
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
belongs_to_polymorphic-0.1.3 lib/belongs_to_polymorphic/associations.rb