diff --git a/app/controllers/forest_liana/associations_controller.rb b/app/controllers/forest_liana/associations_controller.rb index b56770ec..a7186ae5 100644 --- a/app/controllers/forest_liana/associations_controller.rb +++ b/app/controllers/forest_liana/associations_controller.rb @@ -15,7 +15,7 @@ def index respond_to do |format| format.json { render_jsonapi(getter) } - format.csv { render_csv(getter, @association.klass) } + format.csv { render_csv(getter, SchemaUtils.association_ref(@association)) } end rescue => error FOREST_LOGGER.error "Association Index error: #{error}\n#{format_stacktrace(error)}" @@ -104,21 +104,21 @@ def resource_params end def is_sti_model? - @is_sti_model ||= (@association.klass.inheritance_column.present? && - @association.klass.columns.any? { |column| column.name == @association.klass.inheritance_column }) + @is_sti_model ||= (SchemaUtils.association_ref(@association).inheritance_column.present? && + SchemaUtils.association_ref(@association).columns.any? { |column| column.name == SchemaUtils.association_ref(@association).inheritance_column }) end def get_record record - is_sti_model? ? record.becomes(@association.klass) : record + is_sti_model? ? record.becomes(SchemaUtils.association_ref(@association)) : record end def render_jsonapi getter - fields_to_serialize = fields_per_model(params[:fields], @association.klass) + fields_to_serialize = fields_per_model(params[:fields], SchemaUtils.association_ref(@association)) records = getter.records.map { |record| get_record(record) } includes = getter.includes_for_serialization if fields_to_serialize && includes.length > 0 - association_name = ForestLiana.name_for(@association.klass) + association_name = ForestLiana.name_for(SchemaUtils.association_ref(@association)) fields_to_serialize[association_name] += ",#{includes.join(',')}" end diff --git a/app/deserializers/forest_liana/resource_deserializer.rb b/app/deserializers/forest_liana/resource_deserializer.rb index daf3a46a..576e6b67 100644 --- a/app/deserializers/forest_liana/resource_deserializer.rb +++ b/app/deserializers/forest_liana/resource_deserializer.rb @@ -57,13 +57,13 @@ def extract_relationships #if data.blank? #@attributes[name] = nil #else - #@attributes[name] = association.klass.find(data[:id]) + #@attributes[name] = SchemaUtils.association_ref(association).find(data[:id]) #end # ActionController::Parameters do not inherit from Hash anymore # since Rails 5. if (data.is_a?(Hash) || data.is_a?(ActionController::Parameters)) && data[:id] - @attributes[name] = association.klass.find(data[:id]) + @attributes[name] = SchemaUtils.association_ref(association).find(data[:id]) elsif data.blank? @attributes[name] = nil end diff --git a/app/helpers/forest_liana/query_helper.rb b/app/helpers/forest_liana/query_helper.rb index ce359775..7d7c7fc6 100644 --- a/app/helpers/forest_liana/query_helper.rb +++ b/app/helpers/forest_liana/query_helper.rb @@ -2,7 +2,7 @@ module ForestLiana module QueryHelper def self.get_one_associations(resource) SchemaUtils.one_associations(resource) - .select { |association| SchemaUtils.model_included?(association.klass) } + .select { |association| !SchemaUtils.polymorphic?(association) && SchemaUtils.model_included?(association.klass) } end def self.get_one_association_names_symbol(resource) diff --git a/app/serializers/forest_liana/serializer_factory.rb b/app/serializers/forest_liana/serializer_factory.rb index 91c98f84..93d8dac4 100644 --- a/app/serializers/forest_liana/serializer_factory.rb +++ b/app/serializers/forest_liana/serializer_factory.rb @@ -265,7 +265,7 @@ def mixpanel_integration? SchemaUtils.associations(active_record_class).each do |a| begin - if SchemaUtils.model_included?(a.klass) + if SchemaUtils.model_included?(SchemaUtils.association_ref(a)) serializer.send(serializer_association(a), a.name) { if [:has_one, :belongs_to].include?(a.macro) begin diff --git a/app/services/forest_liana/belongs_to_updater.rb b/app/services/forest_liana/belongs_to_updater.rb index e36ee2bd..519ab2e5 100644 --- a/app/services/forest_liana/belongs_to_updater.rb +++ b/app/services/forest_liana/belongs_to_updater.rb @@ -13,7 +13,7 @@ def initialize(resource, association, params) def perform begin @record = @resource.find(@params[:id]) - new_value = @association.klass.find(@data[:id]) if @data && @data[:id] + new_value = SchemaUtils.association_ref(@association).find(@data[:id]) if @data && @data[:id] @record.send("#{@association.name}=", new_value) @record.save diff --git a/app/services/forest_liana/has_many_associator.rb b/app/services/forest_liana/has_many_associator.rb index bef8faf5..33ae8db1 100644 --- a/app/services/forest_liana/has_many_associator.rb +++ b/app/services/forest_liana/has_many_associator.rb @@ -13,7 +13,7 @@ def perform if @data.is_a?(Array) @data.each do |record_added| - associated_records << @association.klass.find(record_added[:id]) + associated_records << SchemaUtils.association_ref(@association).find(record_added[:id]) end end end diff --git a/app/services/forest_liana/has_many_dissociator.rb b/app/services/forest_liana/has_many_dissociator.rb index 905acfc2..fa771120 100644 --- a/app/services/forest_liana/has_many_dissociator.rb +++ b/app/services/forest_liana/has_many_dissociator.rb @@ -25,13 +25,13 @@ def perform if !record_ids.nil? && record_ids.any? if remove_association record_ids.each do |id| - associated_records.delete(@association.klass.find(id)) + associated_records.delete(SchemaUtils.association_ref(@association).find(id)) end end if @with_deletion - record_ids = record_ids.select { |record_id| @association.klass.exists?(record_id) } - @association.klass.destroy(record_ids) + record_ids = record_ids.select { |record_id| SchemaUtils.association_ref(@association).exists?(record_id) } + SchemaUtils.association_ref(@association).destroy(record_ids) end end end diff --git a/app/services/forest_liana/has_many_getter.rb b/app/services/forest_liana/has_many_getter.rb index ec7fc1eb..c6911aee 100644 --- a/app/services/forest_liana/has_many_getter.rb +++ b/app/services/forest_liana/has_many_getter.rb @@ -37,10 +37,10 @@ def records private def compute_includes - @includes = @association.klass + @includes = SchemaUtils.association_ref(@association) .reflect_on_all_associations .select do |association| - inclusion = !association.options[:polymorphic] && + inclusion = !SchemaUtils.polymorphic?(association) && SchemaUtils.model_included?(association.klass) && [:belongs_to, :has_and_belongs_to_many].include?(association.macro) diff --git a/app/services/forest_liana/leaderboard_stat_getter.rb b/app/services/forest_liana/leaderboard_stat_getter.rb index b331df44..6ddf49e9 100644 --- a/app/services/forest_liana/leaderboard_stat_getter.rb +++ b/app/services/forest_liana/leaderboard_stat_getter.rb @@ -3,7 +3,7 @@ class LeaderboardStatGetter < StatGetter def initialize(resource, params) @resource = resource @params = params - @model_relationship = @resource.reflect_on_association(@params[:relationship_field]).klass + @model_relationship = @resource.reflect_on_association(@params[:relationship_field]).klass compute_includes() @label_field = @params[:label_field] @aggregate = @params[:aggregate].downcase diff --git a/app/services/forest_liana/resource_creator.rb b/app/services/forest_liana/resource_creator.rb index 1b9c4d2d..1c16c286 100644 --- a/app/services/forest_liana/resource_creator.rb +++ b/app/services/forest_liana/resource_creator.rb @@ -18,7 +18,7 @@ def perform end set_has_many_relationships rescue ActiveRecord::StatementInvalid => exception - # NOTICE: SQL request cannot be executed properly + # NOTICE: SQL request cannot be executed properly @errors = [{ detail: exception.cause.error }] rescue ForestLiana::Errors::SerializeAttributeBadFormat => exception @errors = [{ detail: exception.message }] @@ -41,7 +41,7 @@ def set_has_many_relationships if data.is_a?(Array) data.each do |x| existing_records = @record.send(name) - new_record = association.klass.find(x[:id]) + new_record = SchemaUtils.association_ref(association).find(x[:id]) if !existing_records.include?(new_record) existing_records << new_record end diff --git a/app/services/forest_liana/resources_getter.rb b/app/services/forest_liana/resources_getter.rb index e73623ce..abbf1f1a 100644 --- a/app/services/forest_liana/resources_getter.rb +++ b/app/services/forest_liana/resources_getter.rb @@ -94,7 +94,7 @@ def compute_includes .map { |field| field.split('.').first.to_sym } includes_has_many = SchemaUtils.many_associations(@resource) - .select { |association| SchemaUtils.model_included?(association.klass) } + .select { |association| SchemaUtils.model_included?(SchemaUtils.association_ref(association)) } .map(&:name) includes_for_smart_search = includes_for_smart_search & includes_has_many diff --git a/app/services/forest_liana/schema_adapter.rb b/app/services/forest_liana/schema_adapter.rb index b5daa051..562d4ace 100644 --- a/app/services/forest_liana/schema_adapter.rb +++ b/app/services/forest_liana/schema_adapter.rb @@ -240,7 +240,7 @@ def add_associations SchemaUtils.associations(@model).each do |association| begin # NOTICE: Delete the association if the targeted model is excluded. - if !SchemaUtils.model_included?(association.klass) + if !SchemaUtils.model_included?(SchemaUtils.association_ref(association)) field = collection.fields.find do |x| x[:field] == association.foreign_key end @@ -272,14 +272,27 @@ def inverse_of(association) automatic_inverse_of(association) end + def polymorphic_inverse_of(association) + active_models = ActiveRecord::Base.descendants + active_models.each do |model| + a = model.reflect_on_all_associations.select{|a| a.options[:as] == association.name } + unless a.empty? + return a.first.name + end + end + end + def automatic_inverse_of(association) - name = association.active_record.name.demodulize.underscore + if SchemaUtils.polymorphic?(association) + polymorphic_inverse_of(association) + else + name = association.active_record.name.demodulize.underscore + inverse_association = association.klass.reflections.keys.find do |k| + k.to_s == name || k.to_s == name.pluralize + end - inverse_association = association.klass.reflections.keys.find do |k| - k.to_s == name || k.to_s == name.pluralize + inverse_association.try(:to_s) end - - inverse_association.try(:to_s) end def get_schema_for_column(column) @@ -313,7 +326,7 @@ def get_schema_for_association(association) field: association.name.to_s, type: get_type_for_association(association), relationship: get_relationship_type(association), - reference: "#{ForestLiana.name_for(association.klass)}.id", + reference: "#{ForestLiana.name_for(SchemaUtils.association_ref(association))}.id", inverse_of: inverse_of(association), is_filterable: !is_many_association(association), is_sortable: true, @@ -500,7 +513,7 @@ def add_validations(column_schema, column) end def get_reference_for(association) - if association.options[:polymorphic] == true + if SchemaUtils.polymorphic?(association) '*.id' else "#{ForestLiana.name_for(association.klass)}.id" diff --git a/app/services/forest_liana/schema_utils.rb b/app/services/forest_liana/schema_utils.rb index d973f4b6..d39c0416 100644 --- a/app/services/forest_liana/schema_utils.rb +++ b/app/services/forest_liana/schema_utils.rb @@ -4,7 +4,7 @@ class SchemaUtils def self.associations(active_record_class) active_record_class.reflect_on_all_associations.select do |association| begin - !polymorphic?(association) && !is_active_type?(association.klass) + !is_active_type?(SchemaUtils.association_ref(association)) rescue FOREST_LOGGER.warn "Unknown association #{association.name} on class #{active_record_class.name}" false @@ -58,6 +58,14 @@ def self.polymorphic?(association) association.options[:polymorphic] end + def self.association_ref(association) + if self.polymorphic?(association) + association.active_record + else + association.klass + end + end + def self.find_model_from_abstract_class(abstract_class, collection_name) abstract_class.subclasses.find do |subclass| if subclass.abstract_class?