require_dependency 'sequencer/unit/import/common/model/mixin/handle_failure' class Sequencer class Unit module Import module Common module Model module Associations class Assign < Sequencer::Unit::Base include ::Sequencer::Unit::Import::Common::Model::Mixin::HandleFailure uses :instance, :associations, :action, :dry_run provides :action def process return if dry_run return if instance.blank? return if associations.blank? && log_associations_error register_changes instance.assign_attributes(associations) rescue => e handle_failure(e) end private # always returns true def log_associations_error return true if %i[failed deactivated].include?(action) logger.error { 'associations cannot be nil' } if associations.nil? true end def register_changes return if !(action == :unchanged && changes.any?) logger.debug { "Changed instance associations: #{changes.inspect}" } state.provide(:action, :updated) end # Why not just use instance.changes? # Because it doesn't include associations # stored on OTHER TABLES (has-one, has-many, HABTM) def changes @changes ||= unfiltered_changes.reject(&method(:no_diff?)) end def unfiltered_changes attrs = associations.keys before = attrs.map(&instance.method(:send)) after = associations.values attrs.zip(before.zip(after)).to_h.with_indifferent_access end def no_diff?(_, values) values.map!(&:sort) if values.all? { |val| val.respond_to?(:sort) } values.map!(&:presence) # [nil, []] -> [nil, nil] values.uniq.length == 1 end end end end end end end end