Finding all by Polymorphic Type in Rails?

情到浓时终转凉″ 提交于 2019-12-03 07:22:20

There is no direct method for this. I wrote this monkey patch for ActiveRecord::Base. This will work for any class.

class ActiveRecord::Base

  def self.all_polymorphic_types(name)
    @poly_hash ||= {}.tap do |hash|
      Dir.glob(File.join(Rails.root, "app", "models", "**", "*.rb")).each do |file|
        klass = File.basename(file, ".rb").camelize.constantize rescue nil
        next unless klass.ancestors.include?(ActiveRecord::Base)

        klass.
          reflect_on_all_associations(:has_many).
          select{ |r| r.options[:as] }.
          each do |reflection|
            (hash[reflection.options[:as]] ||= []) << klass
          end
      end
    end
    @poly_hash[name.to_sym]
  end

end

Now you can do the following:

Assignable.all_polymorphic_types(:assignable).map(&:to_s)
# returns ['Project', 'Event', 'Group']

I created a polymorphic model class with a method 'all' to test this.

class Profile
  # Return all profile instances
  # For class return use 'ret << i' instead of 'ret << i.all'
  def self.all
    ret = []
    subclasses_of(ActiveRecord::Base).each do |i|
      unless i.reflect_on_all_associations.select{|j| j.options[:as] == :profile}.empty?
        ret << i
      end
    end
    ret.flatten
  end

  def self.all_associated
    User.all.map{|u| u.profile }.flatten
  end
end

Here is my app setup:

User < ActiveRecord::Base
  belongs_to :profile, :polymorphic => true
end

Student < ActiveRecord::Base
  has_one :user, :as => :profile
end

You can also try this way.cause above solution doesn't work for me cause i had some mongo's model.

def get_has_many_associations_for_model(associations_name, polymorphic=nil)

  associations_name = associations_name.to_s.parameterize.underscore.pluralize.to_sym
  active_models = ActiveRecord::Base.descendants
  get_model = []
  active_models.each do |model|

    has_many_associations =model.reflect_on_all_associations(:has_many).select{|a|a.name==associations_name }
    has_many_associations = has_many_associations.select{ |a| a.options[:as] == polymorphic.to_s.to_sym} if polymorphic.present?
    get_model << model if has_many_associations.present?

  end
  get_model.map{|a| a.to_s}
end

Anb call it like

get_has_many_associations_for_model("assignments", "assignable")

Here Second parameters is optional for if you want polymorphic records than pass it otherwise leave it as blank.

It will Return Array of Model name as String.

You should be able to just use the associated collection:

model.assignments.all
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!