assign.rb 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. class Sequencer
  3. class Unit
  4. module Import
  5. module Common
  6. module Model
  7. module Associations
  8. class Assign < Sequencer::Unit::Base
  9. include ::Sequencer::Unit::Import::Common::Model::Mixin::HandleFailure
  10. uses :instance, :associations, :action, :dry_run
  11. provides :action
  12. def process
  13. return if dry_run
  14. return if instance.blank?
  15. return if associations.blank? && log_associations_error
  16. register_changes
  17. instance.assign_attributes(associations)
  18. rescue => e
  19. handle_failure(e)
  20. end
  21. private
  22. # always returns true
  23. def log_associations_error
  24. return true if %i[skipped failed deactivated].include?(action)
  25. logger.error { 'associations cannot be nil' } if associations.nil?
  26. true
  27. end
  28. def register_changes
  29. return if !(action == :unchanged && changes.any?)
  30. logger.debug { "Changed instance associations: #{changes.inspect}" }
  31. state.provide(:action, :updated)
  32. end
  33. # Why not just use instance.changes?
  34. # Because it doesn't include associations
  35. # stored on OTHER TABLES (has-one, has-many, HABTM)
  36. def changes
  37. @changes ||= unfiltered_changes.reject { |_attribute, values| no_diff?(values) }
  38. end
  39. def unfiltered_changes
  40. attrs = associations.keys
  41. before = attrs.map { |attribute| instance.send(attribute) }
  42. after = associations.values
  43. attrs.zip(before.zip(after)).to_h.with_indifferent_access
  44. end
  45. def no_diff?(values)
  46. values.map!(&:sort) if values.all? { |val| val.respond_to?(:sort) }
  47. values.map!(&:presence) # [nil, []] -> [nil, nil]
  48. values.uniq.length == 1
  49. end
  50. end
  51. end
  52. end
  53. end
  54. end
  55. end
  56. end