Skip to content

Instantly share code, notes, and snippets.

@leehericks
Last active April 20, 2023 01:18
Show Gist options
  • Save leehericks/4f05b83acae8b188b1693220cd8663ce to your computer and use it in GitHub Desktop.
Save leehericks/4f05b83acae8b188b1693220cd8663ce to your computer and use it in GitHub Desktop.
Alias delegated types
module DelegatedTypeAliasing
extend ActiveSupport::Concern
class_methods do
def delegated_type(role, types:, **options)
if types.is_a?(Hash)
aliases = types.stringify_keys!
types = types.keys
elsif options.delete(:demodulized_aliases)
aliases = generate_delegated_type_demodulized_aliases(types)
else
raise "#{self.model_name}.delegated_type(:#{role}) supplied invalid types:" unless types.is_a?(Array)
aliases = {}
end
super
alias_delegated_types(aliases)
define_singleton_method("#{role}_types") { types.freeze }
define_singleton_method("#{role}_type_aliases") { aliases.freeze }
end
def has_many_delegated_type(role, through:, prefix: nil)
role = role.to_s.singularize
klass = reflect_on_association(through).klass
types = klass.public_send("#{role}_types")
aliases = klass.public_send("#{role}_type_aliases")
types.each do |type|
scope_name = (aliases[type] || type).tableize.gsub("/", "_")
assoc_name = prefix.present? ? "#{prefix}_#{scope_name}" : scope_name
has_many assoc_name.to_sym, through: through, source: role, source_type: type
end
end
private
def generate_delegated_type_demodulized_aliases(types)
types.map do |type|
type_alias = type.demodulize
[type, type_alias] unless type == type_alias
end.compact.to_h
end
def alias_delegated_types(aliases)
aliases.each do |type, type_alias|
scope_name = type.tableize.gsub("/", "_")
singular = scope_name.singularize
query = "#{singular}?"
scope_name_alias = type_alias.tableize.gsub("/", "_")
singular_alias = scope_name_alias.singularize
query_alias = "#{singular_alias}?"
singleton_class.send(:alias_method, :"#{scope_name_alias}", :"#{scope_name}")
alias_method :"#{query_alias}", :"#{query}"
alias_method :"#{singular_alias}", :"#{singular}"
alias_method :"#{singular_alias}_id", :"#{singular}_id"
end
end
end
end
class Lms::Program::Membership < ApplicationRecord
include DelegatedTypeAliasing
belongs_to :program
belongs_to :user
delegated_type :membershipable, types: %w[ Lms::Program::Staffing Lms::Program::Enrollment ], demodulized_aliases: true, inverse_of: :membership, dependent: :destroy
scope :active, -> { where(ends_at: nil) }
validates :user, uniqueness: { scope: [:program, :ends_at] }
def self.create_staffing(program:, user:, manages: false, teaches: false)
create! program: program, user: user, membershipable: Lms::Program::Staffing.new(manages: manages, teaches: teaches)
end
def self.create_enrollment(program:, user:)
create! program: program, user: user, membershipable: Lms::Program::Enrollment.new
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment