Class: ActiveRecord::Duplicator

Inherits:
Object
  • Object
show all
Defined in:
lib/active_record/duplicator.rb,
lib/active_record/duplicator/errors.rb,
lib/active_record/duplicator/session.rb,
lib/active_record/duplicator/version.rb,
lib/active_record/duplicator/handler_api.rb,
lib/active_record/duplicator/association_traversal.rb,
sig/generated/active_record/duplicator.rbs,
sig/generated/active_record/duplicator/errors.rbs,
sig/generated/active_record/duplicator/session.rbs,
sig/generated/active_record/duplicator/version.rbs,
sig/generated/active_record/duplicator/handler_api.rbs,
sig/generated/active_record/duplicator/association_traversal.rbs

Overview

Reusable duplication configuration and entrypoint.

A Duplicator holds only per-model handler registrations; it does not hold any per-run state (the id map lives on Session). Freeze after registering handlers to enforce immutability across many duplication runs.

Example:

duplicator = ActiveRecord::Duplicator.new
duplicator.on(Attachment) { |api, klass, records| ... }
duplicator.freeze

new_root = duplicator.duplicate(old_root, associations: [...]) do |session|
session.mark_skip(tenant)
end

Defined Under Namespace

Classes: AssociationTraversal, DuplicateHandlerError, Error, HandlerApi, InvalidRecordIdError, MissingNewIdError, Session

Constant Summary collapse

VERSION =

Returns:

  • (::String)
"0.5.0"

Instance Method Summary collapse

Constructor Details

#initializeDuplicator

: () -> void



25
26
27
28
# File 'lib/active_record/duplicator.rb', line 25

def initialize
  @handlers = {}
  @skipped_classes = Set.new
end

Instance Method Details

#duplicate(root_record, associations: [], transaction_options: {}, &block) ⇒ void

This method returns an undefined value.

Run one duplication. A fresh Session (with a fresh record id map) is created for every invocation, so state does not leak between runs.

If a block is given it is called with the new Session before duplication starts, letting the caller mark_skip or store_new_id for records that were duplicated elsewhere.

transaction_options is forwarded verbatim to Session#run, which forwards it to root_record.transaction. Default is {} (plain transaction do ... end). : (ActiveRecord::Base, ?associations: untyped, ?transaction_options: Hash[Symbol, untyped]) ?{ (Session) -> void } -> ActiveRecord::Base

Parameters:

  • (ActiveRecord::Base)
  • associations: (Object) (defaults to: [])
  • transaction_options: (Hash[Symbol, untyped]) (defaults to: {})


71
72
73
74
75
# File 'lib/active_record/duplicator.rb', line 71

def duplicate(root_record, associations: [], transaction_options: {}, &block)
  session = Session.new(handlers: @handlers, skipped_classes: @skipped_classes)
  block&.call(session)
  session.run(root_record, associations:, transaction_options:)
end

#freezeself

Prevent further registrations. Also freezes the internal handler map so accidental mutation later fails loudly. : () -> self

Returns:

  • (self)


54
55
56
57
58
# File 'lib/active_record/duplicator.rb', line 54

def freeze
  @handlers.freeze
  @skipped_classes.freeze
  super
end

#mark_skip_class(*klasses) ⇒ void

This method returns an undefined value.

Declare that every record of the given classes must not be duplicated in any subsequent run. See Session#mark_skip_class for the semantics; the Duplicator-level registration is applied to every fresh Session as its baseline, and Session#mark_skip_class can extend it for a single run. Repeated calls with the same class are idempotent. : (*Class) -> void

Parameters:

  • (Class)


47
48
49
# File 'lib/active_record/duplicator.rb', line 47

def mark_skip_class(*klasses)
  @skipped_classes.merge(klasses)
end

#on(klass) {|arg0, arg1, arg2| ... } ⇒ void

This method returns an undefined value.

Register a custom handler for the given model class. See HandlerApi for the API the block receives.

Raises DuplicateHandlerError when the same class is registered twice. : (Class) { (HandlerApi, Class, untyped) -> void } -> void

Parameters:

  • (Class)

Yields:

Yield Parameters:

Yield Returns:

  • (void)


35
36
37
38
39
# File 'lib/active_record/duplicator.rb', line 35

def on(klass, &block)
  raise DuplicateHandlerError, "handler for #{klass} is already registered" if @handlers.key?(klass)

  @handlers[klass] = block
end