1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
# frozen_string_literal: true
require "active_record/fixture_set/table_row"
require "active_record/fixture_set/model_metadata"
module ActiveRecord
class FixtureSet
class TableRows # :nodoc:
class ReflectionProxy # :nodoc:
def initialize(association)
@association = association
end
def join_table
@association.join_table
end
def name
@association.name
end
def primary_key_type
@association.klass.type_for_attribute(@association.klass.primary_key).type
end
end
class HasManyThroughProxy < ReflectionProxy # :nodoc:
def rhs_key
@association.foreign_key
end
def lhs_key
@association.through_reflection.foreign_key
end
def join_table
@association.through_reflection.table_name
end
end
def initialize(table_name, model_class:, fixtures:, config:)
@table_name = table_name
@model_class = model_class
# track any join tables we need to insert later
@tables = Hash.new { |h, table| h[table] = [] }
# ensure this table is loaded before any HABTM associations
@tables[table_name] = nil
build_table_rows_from(fixtures, config)
end
attr_reader :table_name, :model_class
def to_hash
@tables.transform_values { |rows| rows.map(&:to_hash) }
end
def model_metadata
@model_metadata ||= ModelMetadata.new(model_class, table_name)
end
def resolve_sti_reflections(row)
# If STI is used, find the correct subclass for association reflection
reflection_class = reflection_class_for(row)
reflection_class._reflections.each_value do |association|
case association.macro
when :belongs_to
# Do not replace association name with association foreign key if they are named the same
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
if association.polymorphic? && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
# support polymorphic belongs_to as "label (Type)"
row[association.foreign_type] = $1
end
fk_type = reflection_class.type_for_attribute(fk_name).type
row[fk_name] = ActiveRecord::FixtureSet.identify(value, fk_type)
end
when :has_many
if association.options[:through]
add_join_records(row, HasManyThroughProxy.new(association))
end
end
end
end
private
def build_table_rows_from(fixtures, config)
now = config.default_timezone == :utc ? Time.now.utc : Time.now
@tables[table_name] = fixtures.map do |label, fixture|
TableRow.new(
fixture,
table_rows: self,
label: label,
now: now,
)
end
end
def reflection_class_for(row)
if row.include?(model_metadata.inheritance_column_name)
row[model_metadata.inheritance_column_name].constantize rescue model_class
else
model_class
end
end
def add_join_records(row, association)
# This is the case when the join table has no fixtures file
if (targets = row.delete(association.name.to_s))
table_name = association.join_table
column_type = association.primary_key_type
lhs_key = association.lhs_key
rhs_key = association.rhs_key
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
joins = targets.map do |target|
{ lhs_key => row[model_metadata.primary_key_name],
rhs_key => ActiveRecord::FixtureSet.identify(target, column_type) }
end
@tables[table_name].concat(joins)
end
end
end
end
end
|