# frozen_string_literal: true require "fmrest/spyke/portal" module FmRest module Spyke module Model module Associations extend ::ActiveSupport::Concern included do # Keep track of portal options by their FM keys as we could need it # to parse the portalData JSON in JsonParser class_attribute :portal_options, instance_accessor: false, instance_predicate: false, default: {}.freeze class << self; private :portal_options=; end end class_methods do # Based on +has_many+, but creates a special Portal association # instead. # # Custom options: # # * :portal_key - The key used for the portal in the FM Data JSON portalData. # * :attribute_prefix - The prefix used for portal attributes in the FM Data JSON. # # Example: # # has_portal :jobs, portal_key: "JobsTable", attribute_prefix: "Job" # def has_portal(name, options = {}) create_association(name, Portal, options) # Store options for JsonParser to use if needed portal_key = options[:portal_key] || name self.portal_options = portal_options.merge(portal_key.to_s => options.dup.merge(name: name.to_s)).freeze define_method "#{name.to_s.singularize}_ids" do association(name).map(&:id) end end end # Override Spyke's association reader to keep a cache of loaded # portals. Spyke's default behavior is to reload the association # each time. # def association(name) @loaded_portals ||= {} if @loaded_portals.has_key?(name.to_sym) return @loaded_portals[name.to_sym] end super.tap do |assoc| next unless assoc.kind_of?(FmRest::Spyke::Portal) @loaded_portals[name.to_sym] = assoc end end def reload super.tap { @loaded_portals = nil } end def portals self.class.associations.each_with_object([]) do |(key, _), portals| candidate = association(key) next unless candidate.kind_of?(FmRest::Spyke::Portal) portals << candidate end end end end end end