Class: YamlExporter::Nodes::OneReferenceOf

Inherits:
Object
  • Object
show all
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

Constructor Details

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

Returns a new instance of OneReferenceOf.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 21

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

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

  unless singular_association?(of_ref)
    raise ArgumentError,
          "`one #{name.inspect}, of: #{of.inspect}`: `of:` must be a 1:[0,1] association " \
          "(belongs_to or has_one); got #{of_ref.macro}"
  end
end

Instance Attribute Details

#find_byObject (readonly)

Returns the value of attribute find_by.



19
20
21
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 19

def find_by
  @find_by
end

#nameObject (readonly)

Returns the value of attribute name.



19
20
21
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 19

def name
  @name
end

#ofObject (readonly)

Returns the value of attribute of.



19
20
21
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 19

def of
  @of
end

#owner_classObject (readonly)

Returns the value of attribute owner_class.



19
20
21
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 19

def owner_class
  @owner_class
end

Instance Method Details

#export(record, exporter:) ⇒ Object



81
82
83
84
85
86
87
88
89
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 81

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

  through = target.public_send(@of)
  return [@name.to_s, nil] if through.nil?

  [@name.to_s, through.public_send(@find_by)]
end

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



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 58

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

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

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

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

#phaseObject



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

def phase
  :pre_save
end

#schema_fragmentObject



91
92
93
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 91

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

#target_classObject



54
55
56
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 54

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

#yaml_keysObject



50
51
52
# File 'lib/yaml_exporter/nodes/one_reference_of.rb', line 50

def yaml_keys
  [@name.to_s]
end