Module: Utilities::Rails::Transmute
- Defined in:
- lib/utilities/rails/transmute.rb
Class Method Summary collapse
-
.move_associations(source, target) ⇒ void
Move shared associations from one ActiveRecord instance (‘source`) to another (`target`).
- .move_has_many(source, target, reflection) ⇒ Object private
- .move_has_one(source, target, reflection) ⇒ Object private
Class Method Details
.move_associations(source, target) ⇒ void
This method returns an undefined value.
Move shared associations from one ActiveRecord instance (‘source`) to another (`target`).
This is designed for moving associations to a fresh, empty target record (e.g., transmuting a CollectionObject into a FieldOccurrence).
This utility inspects ActiveRecord reflections to find associations that both ‘source` and `target` define. For each shared association:
* has_one – The associated record is reassigned to `target`.
* has_many – Each associated record is reassigned to `target`.
Associations that are skipped:
* belongs_to – Explicitly excluded. These should already be set on target.
* through – Skipped as these are convenience relations built on top of
other associations.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/utilities/rails/transmute.rb', line 31 def self.move_associations(source, target) # Validate project_id match if source.respond_to?(:project_id) && target.respond_to?(:project_id) if source.project_id != target.project_id raise TaxonWorks::Error, "Cannot transmute objects from different projects (source: #{source.project_id}, target: #{target.project_id})" end end source.class.transaction do source.class.reflections.each_value do |reflection| # Skip belongs_to - those should already be set on target next if reflection.macro == :belongs_to # Skip through associations - they're convenience relations next if reflection.[:through] # Only process if target class has the same association next unless target.class.reflections.key?(reflection.name.to_s) case reflection.macro when :has_one move_has_one(source, target, reflection) when :has_many move_has_many(source, target, reflection) end end rescue ActiveRecord::RecordInvalid => e raise TaxonWorks::Error, "Failed to move associations: #{e.}" rescue ActiveRecord::InvalidForeignKey => e raise TaxonWorks::Error, "Failed to move associations: #{e.}" rescue ActiveRecord::RecordNotSaved => e raise TaxonWorks::Error, "Failed to move associations: #{e.}" end end |
.move_has_many(source, target, reflection) ⇒ Object (private)
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/utilities/rails/transmute.rb', line 79 def self.move_has_many(source, target, reflection) source.send(reflection.name).each do |associated| # Skip DWC Occurrence identifiers - target will get its own next if associated.is_a?(Identifier::Global::Uuid::TaxonworksDwcOccurrence) # For polymorphic associations, we need to update both the _id and _type fields if reflection.[:as] # This is a polymorphic association # Hackish: For Global::Uuid, set is_generated to nil to prevent UUID # regeneration during update if associated.class.ancestors.include?(Identifier::Global::Uuid) associated.is_generated = nil end # Some updates are expected to raise here, like CatalogNumber being # moved to FieldOccurrence, etc. associated.update!( reflection.[:as] => target ) else # Regular association - just reassign target.send(reflection.name) << associated end end end |
.move_has_one(source, target, reflection) ⇒ Object (private)
68 69 70 71 72 73 74 75 76 77 |
# File 'lib/utilities/rails/transmute.rb', line 68 def self.move_has_one(source, target, reflection) associated = source.send(reflection.name) return unless associated # Skip dwc_occurrence - target will get its own return if reflection.name.to_s == 'dwc_occurrence' # Update the foreign key to point to target associated.update!(reflection.foreign_key => target.id) end |