indentlabs/notebook

View on GitHub
app/models/concerns/has_content_groupers.rb

Summary

Maintainability
A
3 hrs
Test Coverage
require 'active_support/concern'

# DEPRECATED :)
module HasContentGroupers
  extend ActiveSupport::Concern

  included do
    # Example:
    #   relates :siblings, with: :siblingships, where: { alive: true }, type: :two_way
    #   Defines :siblings and :siblingships relations, their inverses, and accepts_nested_attributes for siblingships
    def self.relates relation, with:#, where: {}
      singularized_relation = relation.to_s.singularize
      connecting_class      = with.to_s.singularize.camelize.constantize
      connecting_class_name = with

      if relation == :deity_characters
        # sadface, SADFACE
        singularized_relation = :deity
      end

      # Fetch the connecting class's through class (e.g. Character for sibling_id).
      # If there isn't one defined, it means it already maps to a model (e.g. race_id),
      # so we can use the name as the class as well.
      belongs_to_relations = connecting_class.reflect_on_all_associations(:belongs_to)
      through_relation = belongs_to_relations.detect do |relation| # sibling
        # sadface
        if relation.name == :deity_character && singularized_relation == :deity
          true
        else
          relation.name.to_s == singularized_relation
        end
      end
      if through_relation.options.key?(:class_name)
        through_relation_class = through_relation.options[:class_name] # Character
      else
        through_relation_class = through_relation.name.to_s.titleize # Character
      end

      # Store all added relations on the config object, so we can dynamically
      # fetch them all whenever needed. These are used to find all relations
      # where a particular page is the target of a content_grouper, rather than
      # the parent (e.g. one of its has_many's).
      Rails.application.config.content_relations[through_relation_class] ||= {}
      Rails.application.config.content_relations[through_relation_class][connecting_class.name] = \
        {                                         # ['Character'][:siblings] = {
          with:          with,                    #   with:          :siblingships,
          related_class: connecting_class,        #   related_class: Siblingship,
          inverse_class: name,                    #   inverse_class: 'Character',
          relation_text: singularized_relation,   #   relation_text: "Sibling"
          through_relation: singularized_relation #   through_relation: 'Sibling'
        }                                         # }
      
      # The same thing but keyed off inverse class, instead of linked class
      # e.g. Character has raceships (Character -> Race) instead of Race having raceships
      Rails.application.config.inverse_content_relations[name] ||= {}
      Rails.application.config.inverse_content_relations[name][connecting_class.name] = \
        {                                         # ['Character'][:siblings] = {
          with:          with,                    #   with:          :siblingships,
          related_class: connecting_class,        #   related_class: Siblingship,
          inverse_class: name,                    #   inverse_class: 'Character',
          relation_text: singularized_relation,   #   relation_text: "Sibling"
          through_relation: singularized_relation #   through_relation: 'Sibling'
        }                                         # }


      # Siblingships
      has_many connecting_class_name, dependent: :destroy

      # Siblings
      has_many relation,
        through: connecting_class_name

      # inverse_siblingships
      has_many "inverse_#{connecting_class_name}".to_sym,
        class_name: "#{singularized_relation.capitalize}",
        foreign_key: "#{singularized_relation}_id"

      # inverse_siblings
      has_many "inverse_#{relation}".to_sym,
        through: "inverse_#{connecting_class_name}".to_sym,
        source: name.downcase

      accepts_nested_attributes_for connecting_class_name,
        reject_if: :all_blank,
        allow_destroy: true
    end
  end
end