module SDG::Relatable extend ActiveSupport::Concern included do has_many :sdg_relations, as: :relatable, dependent: :destroy, class_name: "SDG::Relation" %w[SDG::Goal SDG::LocalTarget].each do |sdg_type| has_many sdg_type.constantize.table_name.to_sym, through: :sdg_relations, source: :related_sdg, source_type: sdg_type end has_many :sdg_global_targets, through: :sdg_relations, source: :related_sdg, source_type: "SDG::Target" has_one :sdg_review, as: :relatable, dependent: :destroy, class_name: "SDG::Review" end class_methods do def by_goal(code) by_sdg_related(:sdg_goals, code) end def by_target(code) if SDG::Target.find_by(code: code) by_sdg_related(:sdg_global_targets, code) else by_sdg_related(:sdg_local_targets, code) end end def by_sdg_related(association, code) return all if code.blank? sdg_class = reflect_on_association(association).options[:source_type].constantize joins(association).merge(sdg_class.where(code: code)) end def sdg_reviewed joins(:sdg_review) end def pending_sdg_review where.missing(:sdg_review) end end def related_sdgs sdg_relations.map(&:related_sdg) end def sdg_targets sdg_global_targets + sdg_local_targets end def sdg_targets=(targets) global_targets, local_targets = targets.partition { |target| target.class.name == "SDG::Target" } transaction do self.sdg_global_targets = global_targets self.sdg_local_targets = local_targets end end def sdg_goal_list sdg_goals.order(:code).map(&:code).join(", ") end def sdg_target_list sdg_targets.sort.map(&:code).join(", ") end def related_sdg_list related_sdgs.sort.map(&:code).join(", ") end def related_sdg_list=(codes) target_codes, goal_codes = codes.tr(" ", "").split(",").partition { |code| code.include?(".") } local_targets_codes, global_targets_codes = target_codes.partition { |code| code.split(".")[2] } global_targets = global_targets_codes.map { |code| SDG::Target[code] } local_targets = local_targets_codes.map { |code| SDG::LocalTarget[code] } goals = goal_codes.map { |code| SDG::Goal[code] } transaction do self.sdg_local_targets = local_targets self.sdg_global_targets = global_targets self.sdg_goals = (global_targets.map(&:goal) + local_targets.map(&:goal) + goals).uniq end end end