Class: YamlExporter::Nodes::OneReferenceOf

Inherits:
Object
  • Object
show all
Includes:
OfResolution
Defined in:
lib/yaml_exporter/nodes/one_reference_of.rb

Overview

one :assoc, find_by: :col, of: :nested_assoc

Identifies the target record indirectly: the YAML value is looked up on a related model (of:) rather than on the target itself.

Example: Book belongs_to :responsible_editor (CorporateUser), and CorporateUser belongs_to :user (User with a slug). Declaring one :responsible_editor, find_by: :slug, of: :user stores the User's slug in the YAML and resolves the CorporateUser on import by reversing the FK.

Only 1:[0,1] of: associations are permitted (belongs_to or has_one). Phase: :pre_save (sets the FK before record.save!).

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from OfResolution

#find_target_via, #of_class, #of_reflection, #of_value_for, #resolve_target_by_of, #singular_of_association?, #validate_of_reflection!

Constructor Details

#initialize(name:, owner_class:, find_by:, of:) ⇒ OneReferenceOf

Returns a new instance of OneReferenceOf.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 23

def initialize(name:, owner_class:, find_by:, of:)
  @name = name.to_sym
  @owner_class = owner_class
  @find_by = find_by.to_sym
  @of = of.to_sym

  reflection = owner_class.reflect_on_association(@name)
  unless reflection
    raise ArgumentError,
          "`one #{name.inspect}`: #{owner_class} has no association `#{name}`"
  end

  validate_of_reflection!("one #{name.inspect}")
end

Instance Attribute Details

#find_byObject (readonly)

Returns the value of attribute find_by.



21
22
23
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 21

def find_by
  @find_by
end

#nameObject (readonly)

Returns the value of attribute name.



21
22
23
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 21

def name
  @name
end

#ofObject (readonly)

Returns the value of attribute of.



21
22
23
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 21

def of
  @of
end

#owner_classObject (readonly)

Returns the value of attribute owner_class.



21
22
23
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 21

def owner_class
  @owner_class
end

Instance Method Details

#export(record, exporter:) ⇒ Object



73
74
75
76
77
78
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 73

def export(record, exporter:)
  target = record.public_send(@name)
  return [@name.to_s, nil] if target.nil?

  [@name.to_s, of_value_for(target)]
end

#import(record, data, path:, importer:) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 50

def import(record, data, path:, importer:)
  value = data.key?(@name.to_s) ? data[@name.to_s] : nil

  if value.nil?
    record.public_send("#{@name}=", nil)
    return
  end

  related = of_class.find_by(@find_by => value)
  unless related
    raise ActiveRecord::RecordNotFound,
          "no #{of_class} with #{@find_by}=#{value.inspect}"
  end

  target = find_target_via(related)
  unless target
    raise ActiveRecord::RecordNotFound,
          "no #{target_class} linked to #{of_class} #{@find_by}=#{value.inspect} via `#{@of}`"
  end

  record.public_send("#{@name}=", target)
end

#phaseObject



38
39
40
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 38

def phase
  :pre_save
end

#schema_fragmentObject



80
81
82
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 80

def schema_fragment
  { @name => { type: TypeInference.schema_type_for(of_class, @find_by) } }
end

#target_classObject



46
47
48
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 46

def target_class
  @target_class ||= @owner_class.reflect_on_association(@name).klass
end

#yaml_keysObject



42
43
44
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 42

def yaml_keys
  [@name.to_s]
end