Module: RailsOtelContext::ActiveRecordContext::ScopeNameTracking

Defined in:
lib/rails_otel_context/activerecord_context.rb

Overview

Wraps scope-generated class methods to store the scope name on the Relation.

Instance Method Summary collapse

Instance Method Details

#scope(name, body) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/rails_otel_context/activerecord_context.rb', line 147

def scope(name, body, &)
  # Guard against double-wrapping on class reload in development.
  # Marked BEFORE super so ClassMethodScopeTracking's
  # singleton_method_added hook (which fires for both the scope macro's
  # definition and our redefinition below) sees the name as owned by
  # this module and skips it.
  @_otel_wrapped_scopes ||= {}
  return super if @_otel_wrapped_scopes[name]

  @_otel_wrapped_scopes[name] = true
  super

  name_str   = name.to_s.freeze
  alias_name = :"__otel_scope_orig_#{name}"
  # Alias instead of capturing a bound Method: a bound Method locks self
  # to the defining class, so inherited scopes would run with self =
  # parent and re-evaluate default_scope in the wrong class context.
  # send(alias_name) dispatches with self = the actual receiver.
  singleton_class.alias_method(alias_name, name)
  define_singleton_method(name) do |*args, **kwargs, &blk|
    relation = send(alias_name, *args, **kwargs, &blk)
    if relation.is_a?(::ActiveRecord::Relation)
      relation.instance_variable_set(:@_otel_scope_name, name_str)
    end
    relation
  end
end