Module: RactorRailsShim::ReflectionThroughPatch

Includes:
ReflectionMemoPatch
Defined in:
lib/ractor_rails_shim/patches/activerecord_reflection.rb

Instance Method Summary collapse

Methods included from ReflectionMemoPatch

#rrs_refl_cache

Instance Method Details

#association_primary_key(klass = nil) ⇒ Object



197
198
199
200
201
202
203
# File 'lib/ractor_rails_shim/patches/activerecord_reflection.rb', line 197

def association_primary_key(klass = nil)
  if primary_key = actual_source_reflection.options[:primary_key]
    rrs_refl_cache[[object_id, :association_primary_key, klass]] ||= -primary_key.to_s
  else
    rrs_refl_cache[[object_id, :association_primary_key, klass]] ||= primary_key(klass || self.klass)
  end
end

#check_validity!Object

ThroughReflection has its OWN check_validity! (distinct from AssociationReflection#check_validity!) that writes @validated on the frozen, shared reflection — raises FrozenError in a worker Ractor. Reimplement it to store the validated flag in the per-worker cache instead. The body mirrors Rails' ThroughReflection#check_validity! (minus the @validated write).



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/ractor_rails_shim/patches/activerecord_reflection.rb', line 240

def check_validity!
  cache = rrs_refl_cache
  return if cache[[object_id, :validated]]

  if through_reflection.nil?
    raise ::ActiveRecord::HasManyThroughAssociationNotFoundError.new(active_record, self)
  end

  if through_reflection.polymorphic?
    if has_one?
      raise ::ActiveRecord::HasOneAssociationPolymorphicThroughError.new(active_record.name, self)
    else
      raise ::ActiveRecord::HasManyThroughAssociationPolymorphicThroughError.new(active_record.name, self)
    end
  end

  if source_reflection.nil?
    raise ::ActiveRecord::HasManyThroughSourceAssociationNotFoundError.new(self)
  end

  if options[:source_type] && !source_reflection.polymorphic?
    raise ::ActiveRecord::HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection)
  end

  if source_reflection.polymorphic? && options[:source_type].nil?
    raise ::ActiveRecord::HasManyThroughAssociationPolymorphicSourceError.new(active_record.name, self, source_reflection)
  end

  if has_one? && through_reflection.collection?
    raise ::ActiveRecord::HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection)
  end

  if parent_reflection.nil?
    reflections = active_record.normalized_reflections.keys

    if reflections.index(through_reflection.name) > reflections.index(name)
      raise ::ActiveRecord::HasManyThroughOrderError.new(active_record.name, self, through_reflection)
    end
  end

  check_validity_of_inverse!

  cache[[object_id, :validated]] = true
end

#deprecated_nested_reflectionsObject



285
286
287
# File 'lib/ractor_rails_shim/patches/activerecord_reflection.rb', line 285

def deprecated_nested_reflections
  rrs_refl_cache[[object_id, :deprecated_nested_reflections]] ||= collect_deprecated_nested_reflections
end

#klassObject



193
194
195
# File 'lib/ractor_rails_shim/patches/activerecord_reflection.rb', line 193

def klass
  rrs_refl_cache[[object_id, :klass]] ||= delegate_reflection.klass
end

#source_reflection_nameObject



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/ractor_rails_shim/patches/activerecord_reflection.rb', line 205

def source_reflection_name
  rrs_refl_cache[[object_id, :source_reflection_name]] ||= begin
    # The constructor sets @source_reflection_name from options[:source]
    # (e.g. has_one :avatar_blob, through: :avatar_attachment, source: :blob
    # sets it to :blob). If already set, use it — the fallback computation
    # below derives from `name` (e.g. :avatar_blob) and would NOT find the
    # :blob association on the through model.
    names = if options[:source]
      [options[:source]]
    else
      [name.to_s.singularize, name].collect(&:to_sym).uniq
    end
    names = names.find_all { |n|
      through_reflection.klass._reflect_on_association(n)
    }

    if names.length > 1
      raise AmbiguousSourceReflectionForThroughAssociation.new(
        active_record.name,
        through_reflection.name,
        source_reflection.plural_name,
        names
      )
    end

    names.first
  end
end