Skip to content

Instantly share code, notes, and snippets.

@woahdae
Last active February 3, 2025 21:08
Show Gist options
  • Save woahdae/44ffff96096c71c780aecffdb4c4c53f to your computer and use it in GitHub Desktop.
Save woahdae/44ffff96096c71c780aecffdb4c4c53f to your computer and use it in GitHub Desktop.
Module to use the Gerund pattern on ActiveRecord models
# frozen_string_literal: true
module Gerund
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
delegate :model_name,
:sti_name,
:finder_needs_type_condition?,
:_to_partial_path,
to: :superclass
end
# Not great to monkeypatch this, but it's the least amount of code
# that does what we want. The issue here is #becomes is super handy
# with gerunds, but the instance returned from #becomes has @attributes
# literally as a pointer to the original attributes hash. This is a
# problem if our subclass defines more attributes with the ::attribute method
# - assignment won't work because the parent instance attributes won't have
# the subclass' attributes defined. This monkeypatch fixes that, just in time
# for anything that depends on these attributes, including `after_initialize`
# callbacks.
def _run_initialize_callbacks
extra_attrs = self.class._default_attributes.keys - @attributes.keys
# Copy over any extra attributes from the gerund to the original attribute
# set. Personally I'd like it to be a new set of attributes, but our code
# accidentally depends on this in a couple places, and I guess I'd rather not
# have it two ways so let's do it the way Rails ships with.
extra_attrs.each do |attr|
@attributes.instance_variable_get(:@attributes)[attr] =
self.class._default_attributes.instance_variable_get(:@attributes)[attr]
end
super
end
# GlobalID depends on the model to get class_name, rather than passing
# it in directly. Maybe someday we can try to get GlobalID to be easier
# to work with in this way; until then, this works.
def to_global_id(*args)
becomes(self.class.superclass).to_global_id(*args)
end
alias :to_gid :to_global_id
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment