lib/has_many_polymorphic/has_many_polymorphic.rb
def has_many_polymorphic(name, options = {})
        target_class_name = self.name
        instance_array_name = "#{name}_array".to_sym

        #declare array to related models
        attr_accessor instance_array_name

        #create the has_many relationship
        has_many options[:through], :dependent => :destroy

        #create the has_many relationship for each model
        options[:models].each do |model|
          has_many model.to_sym, -> { where("#{options[:through]}.#{name.to_s.singularize}_type = ?", model.to_s.classify) },
            :through => options[:through],
            :source => model.to_s.singularize,
            :dependent => :destroy
        end

        #modify the through class to add the belongs to relationships
        options[:through].to_s.classify.constantize.class_exec do
          options[:models].each do |model|
            belongs_to model.to_s.singularize.to_sym, :class_name => model.to_s.classify, :foreign_key => "#{name.to_s.singularize}_id"
          end
        end

        #I want to keep the << and push methods of array so this helps to keep them.
        define_method name do
          #used the declared instance variable array
          records = self.send(instance_array_name.to_s)
          records = records || []
          options[:models].each do |model|
            records = records | self.send(model.to_s)
          end

          #set it back to the instance variable
          self.send("#{instance_array_name.to_s}=", records)

          records
        end

        #before we save this model make sure you save all the relationships.
        before_save do |record|
          record.send(name).each do |reln_record|
            #handle STI get superclass class_name if not sub class of ActiveRecord::Base
            klass_name = (reln_record.class.superclass == ::ApplicationRecord) ? reln_record.class.name : reln_record.class.superclass.name
            conditions = "#{name.to_s.singularize}_id = #{reln_record.id} and #{name.to_s.singularize}_type = '#{klass_name}'"
            exisiting_record = record.send("#{options[:through]}").where(conditions).first

            if exisiting_record.nil?
              values_hash = {}
              values_hash["#{record.class.name.underscore}_id"] = record.id
              values_hash["#{name.to_s.singularize}_type"] = klass_name
              values_hash["#{name.to_s.singularize}_id"] = reln_record.id

              options[:through].to_s.classify.constantize.create(values_hash)
            end
          end
        end

        #add the relationship to the models.
        options[:models].each do |model|
          model.to_s.classify.constantize.class_exec do
            has_many options[:through], :as => name.to_s.singularize, :dependent => :destroy
            has_many target_class_name.tableize.to_sym, :through => options[:through], :dependent => :destroy
          end
        end

      end
##
#  HasManyPolymorphic
#  This mixin adds a has many polymorphic relationship to a model and creates all the relationships needed
#  by rails to handle it.
#
#  Params
#
#  Name - name of the relationship, there is a convention that whatever name you choose, the polymorphic
#  table columns on your through table should match.
#
#  Options
#   - through - the model that handles the through relationship
#   - models  - models that should be included in this polymophic relationship
#
#
#  One method is added for you to use
#
#  - {name param}
#    - the name of your relationship is used for the method name of this method. it will return
#    an array of the models that are related via the has_many relationships
#
#  There is an after_save call back that will save the relationships when they are added or removed
#  If you want to remove a relationship the models need to be destroyed and this model reloaded.
#
#  Example Usage
#
#  class PreferenceType < ActiveRecord::Base
#   has_many_polymorphic :preferenced_records,
#       :through => :valid_preference_types,
#       :models => [:desktops, :organizers]
#  end
#
#  this gives you the following
#
#  preferenceType = PreferenceType.first
#  preferenceType.desktops
#  preferenceType.organizers
#
#  and
#
#  preferenceType.preferenced_records
#
#  which is a concatentated array of the models. You also get the following
#
#  desktop = Desktop.first
#  desktop.preference_types
#
#  organizer = Organizer.first
#  organizer.preference_types
##
HasManyPolymorphic
This mixin adds a has many polymorphic relationship to a model and creates all the relationships needed
by rails to handle it.

Params

name of the relationship, there is a convention that whatever name you choose, the polymorphic
table columns on your through table should match.

Options
through - the model that handles the through relationship
models  - models that should be included in this polymophic relationship

One method is added for you to use

{name param}
the name of your relationship is used for the method name of this method. it will return
an array of the models that are related via the has_many relationships

There is an after_save call back that will save the relationships when they are added or removed
If you want to remove a relationship the models need to be destroyed and this model reloaded.

Example Usage



this gives you the following



and



which is a concatentated array of the models. You also get the following




HasManyPolymorphic This mixin adds a has many polymorphic relationship to a model and creates all the relationships needed by rails to handle it . Params name of the relationship there is a convention that whatever name you choose the polymorphic table columns on your through table should match . Options through - the model that handles the through relationship models - models that should be included in this polymophic relationship One method is added for you to use { name param } the name of your relationship is used for the method name of this method . it will return an array of the models that are related via the has_many relationships There is an after_save call back that will save the relationships when they are added or removed If you want to remove a relationship the models need to be destroyed and this model reloaded . Example Usage this gives you the following and which is a concatentated array of the models . You also get the following
def has_many_polymorphic(name, options = {})
        target_class_name = self.name
        instance_array_name = "#{name}_array".to_sym
        attr_accessor instance_array_name
        has_many options[:through], :dependent => :destroy
         for each model
        options[:models].each do |model|
          has_many model.to_sym, -> { where("#{options[:through]}.#{name.to_s.singularize}_type = ?", model.to_s.classify) },
            :through => options[:through],
            :source => model.to_s.singularize,
            :dependent => :destroy
        end
        options[:through].to_s.classify.constantize.class_exec do
          options[:models].each do |model|
            belongs_to model.to_s.singularize.to_sym, :class_name => model.to_s.classify, :foreign_key => "#{name.to_s.singularize}_id"
          end
        end
        define_method name do
          records = self.send(instance_array_name.to_s)
          records = records || []
          options[:models].each do |model|
            records = records | self.send(model.to_s)
          end
          self.send("#{instance_array_name.to_s}=", records)
          records
        end
        before_save do |record|
          record.send(name).each do |reln_record|
            klass_name = (reln_record.class.superclass == ::ApplicationRecord) ? reln_record.class.name : reln_record.class.superclass.name
            conditions = "#{name.to_s.singularize}_id = #{reln_record.id} and #{name.to_s.singularize}_type = '#{klass_name}'"
            exisiting_record = record.send("#{options[:through]}").where(conditions).first
            if exisiting_record.nil?
              values_hash = {}
              values_hash["#{record.class.name.underscore}_id"] = record.id
              values_hash["#{name.to_s.singularize}_type"] = klass_name
              values_hash["#{name.to_s.singularize}_id"] = reln_record.id
              options[:through].to_s.classify.constantize.create(values_hash)
            end
          end
        end
        options[:models].each do |model|
          model.to_s.classify.constantize.class_exec do
            has_many options[:through], :as => name.to_s.singularize, :dependent => :destroy
            has_many target_class_name.tableize.to_sym, :through => options[:through], :dependent => :destroy
          end
        end
      end
def has_many_polymorphic ( name , options = { } ) target_class_name = self . name instance_array_name = "#{name}_array" . to_sym attr_accessor instance_array_name has_many options [ :through ] , :dependent => :destroy options [ :models ] . each do | model | has_many model . to_sym , -> { where ( "#{options[:through]}.#{name.to_s.singularize}_type = ?" , model . to_s . classify ) } , :through => options [ :through ] , :source => model . to_s . singularize , :dependent => :destroy end options [ :through ] . to_s . classify . constantize . class_exec do options [ :models ] . each do | model | belongs_to model . to_s . singularize . to_sym , :class_name => model . to_s . classify , :foreign_key => "#{name.to_s.singularize}_id" end end define_method name do records = self . send ( instance_array_name . to_s ) records = records || [ ] options [ :models ] . each do | model | records = records | self . send ( model . to_s ) end self . send ( "#{instance_array_name.to_s}=" , records ) records end before_save do | record | record . send ( name ) . each do | reln_record | klass_name = ( reln_record . class . superclass == :: ApplicationRecord ) ? reln_record . class . name : reln_record . class . superclass . name conditions = "#{name.to_s.singularize}_id = #{reln_record.id} and #{name.to_s.singularize}_type = '#{klass_name}'" exisiting_record = record . send ( "#{options[:through]}" ) . where ( conditions ) . first if exisiting_record . nil? values_hash = { } values_hash [ "#{record.class.name.underscore}_id" ] = record . id values_hash [ "#{name.to_s.singularize}_type" ] = klass_name values_hash [ "#{name.to_s.singularize}_id" ] = reln_record . id options [ :through ] . to_s . classify . constantize . create ( values_hash ) end end end options [ :models ] . each do | model | model . to_s . classify . constantize . class_exec do has_many options [ :through ] , :as => name . to_s . singularize , :dependent => :destroy has_many target_class_name . tableize . to_sym , :through => options [ :through ] , :dependent => :destroy end end end
HasManyPolymorphic
This mixin adds a has many polymorphic relationship to a model and creates all the relationships needed
by rails to handle it.
HasManyPolymorphic This mixin adds a has many polymorphic relationship to a model and creates all the relationships needed by rails to handle it .
#declare array to related models #create the has_many relationship #create the has_many relationship for each model #modify the through class to add the belongs to relationships #I want to keep the << and push methods of array so this helps to keep them. #used the declared instance variable array #set it back to the instance variable #before we save this model make sure you save all the relationships. #handle STI get superclass class_name if not sub class of ActiveRecord::Base #add the relationship to the models.
name
options