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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
# frozen_string_literal: true
module ActiveRecord
class FixtureSet
class TableRow # :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(fixture, table_rows:, label:, now:)
@table_rows = table_rows
@label = label
@now = now
@row = fixture.to_hash
fill_row_model_attributes
end
def to_hash
@row
end
private
def model_metadata
@table_rows.model_metadata
end
def model_class
@table_rows.model_class
end
def fill_row_model_attributes
return unless model_class
fill_timestamps
interpolate_label
generate_primary_key
resolve_enums
resolve_sti_reflections
end
def reflection_class
@reflection_class ||= if @row.include?(model_metadata.inheritance_column_name)
@row[model_metadata.inheritance_column_name].constantize rescue model_class
else
model_class
end
end
def fill_timestamps
# fill in timestamp columns if they aren't specified and the model is set to record_timestamps
if model_class.record_timestamps
model_metadata.timestamp_column_names.each do |c_name|
@row[c_name] = @now unless @row.key?(c_name)
end
end
end
def interpolate_label
# interpolate the fixture label
@row.each do |key, value|
@row[key] = value.gsub("$LABEL", @label.to_s) if value.is_a?(String)
end
end
def generate_primary_key
# generate a primary key if necessary
if model_metadata.has_primary_key_column? && !@row.include?(model_metadata.primary_key_name)
@row[model_metadata.primary_key_name] = ActiveRecord::FixtureSet.identify(
@label, model_metadata.primary_key_type
)
end
end
def resolve_enums
model_class.defined_enums.each do |name, values|
if @row.include?(name)
@row[name] = values.fetch(@row[name], @row[name])
end
end
end
def resolve_sti_reflections
# If STI is used, find the correct subclass for association reflection
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(HasManyThroughProxy.new(association))
end
end
end
end
def add_join_records(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
@table_rows.tables[table_name].concat(joins)
end
end
end
end
end
|