live_fixtures 3.1.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +22 -2
- data/lib/live_fixtures/export/fixture.rb +68 -62
- data/lib/live_fixtures/export.rb +84 -82
- data/lib/live_fixtures/import/fixtures.rb +96 -92
- data/lib/live_fixtures/import/insertion_order_computer.rb +104 -102
- data/lib/live_fixtures/import.rb +176 -171
- data/lib/live_fixtures/version.rb +3 -1
- data/lib/live_fixtures.rb +13 -10
- metadata +9 -162
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 44657be02cbaa2b748a3b9391e43e96aba4590b228f9b25203f65e877ec2137c
|
4
|
+
data.tar.gz: 5ef93aeac3ebf8d6ec8ae6908b558c2fc28d481faa5ea68765d9fcbe6bf55694
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 050b48d22551468a7dfa49daf66b03c0965a8c1e392b8620430a6a37e641407ac541ca4d6e57ee078c630c3e02e1561740b8896aefe1ea73e5fc13aa72ce2108
|
7
|
+
data.tar.gz: 79958eed4b5831daa43c5af847fd3e74bafce50bec42943528c1f6ad1939179890d82517f0c995b2ee2da063fb1786ace7c7b1dfc54c268b468ac9a99e03526f
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
4
4
|
|
5
|
+
## [4.0.0] - Unreleased
|
6
|
+
### Added
|
7
|
+
Support for Ruby 3.2, active record 7
|
8
|
+
|
9
|
+
### Removed
|
10
|
+
Dropped support for Ruby < 3.2, Rails < 7.0
|
11
|
+
|
5
12
|
## [3.1.1] - 2024-04-04
|
6
13
|
### Fixed
|
7
14
|
Expose the `skip_attributes` option in LiveFixtures::Export.
|
data/README.md
CHANGED
@@ -285,11 +285,31 @@ reflected in the order of the `@table_names` array.
|
|
285
285
|
|
286
286
|
## Development
|
287
287
|
|
288
|
+
This project uses nix to manage the dev environment.
|
289
|
+
|
290
|
+
This project additionally uses
|
291
|
+
- [direnv](https://github.com/direnv/direnv)
|
292
|
+
- flakes
|
293
|
+
|
294
|
+
If you don't have flakes enabled, you can enable them by adding `experimental-features = flakes` to your `~/.config/nix/nix.conf` file.
|
295
|
+
(or running )
|
296
|
+
|
297
|
+
typing `direnv allow` loads the dev environment including a compatible ruby, sqlite, and gems.
|
298
|
+
|
299
|
+
To modify gem dependencies, use the bundle wrappers
|
300
|
+
- `bundle-lock` to update the lockfile
|
301
|
+
- `bundle-update` to update gems & the lockfile
|
302
|
+
then run `bundix` to update the `gemset.nix` file.
|
303
|
+
|
304
|
+
### Usage Without Nix
|
305
|
+
|
306
|
+
Usage without nix is unsupported but may work anyways. Try the following:
|
307
|
+
|
288
308
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
289
309
|
|
290
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
310
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
291
311
|
|
292
|
-
|
312
|
+
Note: We only support adding gems and dependencies using nix.
|
293
313
|
|
294
314
|
## Contributing
|
295
315
|
|
@@ -1,81 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Exposes functionality to serialize an ActiveRecord record (a model) into a
|
2
4
|
# YAML fixture.
|
3
|
-
module LiveFixtures
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
# @param model [ActiveRecord::Base] an ActiveRecord record to serialize
|
8
|
-
# @param references [Symbol, Array<Symbol>] the names of associations whose foreign_keys should be replaced with references
|
9
|
-
# @param more_attributes [Hash{String => Time, DateTime, Date, Hash, String, LiveFixtures::Export::Template, LiveFixtures::Export::Reference, #to_s}] a hash of additional attributes to serialize with each record.
|
10
|
-
# @param skip_attributes [Array<String>] a list of attributes to skip when serializing the model
|
11
|
-
# @return [String] the model serialized in YAML, with specified foreign_keys replaced by references, including additional attributes.
|
12
|
-
def to_yaml(model, references = [], more_attributes = {}, skip_attributes: [])
|
13
|
-
table_name = model.class.table_name
|
5
|
+
module LiveFixtures
|
6
|
+
module Export
|
7
|
+
module Fixture
|
8
|
+
module_function
|
14
9
|
|
15
|
-
|
10
|
+
# YAML-Serializes the provided model, including any references and additional
|
11
|
+
# attribtues.
|
12
|
+
# @param model [ActiveRecord::Base] an ActiveRecord record to serialize
|
13
|
+
# @param references [Symbol, Array<Symbol>] the names of associations whose foreign_keys should be replaced with references
|
14
|
+
# @param more_attributes [Hash{String => Time, DateTime, Date, Hash, String, LiveFixtures::Export::Template, LiveFixtures::Export::Reference, #to_s}] a hash of additional attributes to serialize with each record.
|
15
|
+
# @param skip_attributes [Array<String>] a list of attributes to skip when serializing the model
|
16
|
+
# @return [String] the model serialized in YAML, with specified foreign_keys replaced by references, including additional attributes.
|
17
|
+
def to_yaml(model, references = [], more_attributes = {}, skip_attributes: [])
|
18
|
+
table_name = model.class.table_name
|
16
19
|
|
17
|
-
|
18
|
-
#{table_name}_#{model.id || SecureRandom.uuid.underscore}:
|
19
|
-
#{yml_attributes(model, more_attributes, skip_attributes)}
|
20
|
+
more_attributes.merge! attributes_from_references(model, references)
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
<<~YML
|
23
|
+
#{table_name}_#{model.id || SecureRandom.uuid.underscore}:
|
24
|
+
#{yml_attributes(model, more_attributes, skip_attributes)}
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
Array(references).each do |assoc_name|
|
26
|
+
YML
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
private_class_method def attributes_from_references(model, references)
|
30
|
+
{}.tap do |options|
|
31
|
+
Array(references).each do |assoc_name|
|
32
|
+
if model.respond_to? assoc_name # need to check #respond_to? because some assoc only exist in certain subclasses
|
33
|
+
assoc_model = model.send assoc_name
|
34
|
+
end
|
31
35
|
|
32
|
-
|
33
|
-
|
36
|
+
if assoc_model.present?
|
37
|
+
options["#{assoc_name}_id"] = LiveFixtures::Export::Reference.new(assoc_name, assoc_model)
|
38
|
+
end
|
39
|
+
end
|
34
40
|
end
|
35
41
|
end
|
36
|
-
end
|
37
|
-
end
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
private_class_method def yml_attributes(model, more_attributes, skip_attributes)
|
44
|
+
model.attributes.except('id').merge(more_attributes).map do |name, value|
|
45
|
+
next if value.nil?
|
46
|
+
next if skip_attributes.include?(name)
|
43
47
|
|
44
|
-
|
45
|
-
|
46
|
-
|
48
|
+
serialize_attribute(model, name, value)
|
49
|
+
end.compact.join("\n ")
|
50
|
+
end
|
47
51
|
|
48
|
-
|
49
|
-
|
52
|
+
private_class_method def serialize_attribute(model, name, value)
|
53
|
+
attribute_type = model.class.type_for_attribute(name)
|
50
54
|
|
51
|
-
|
52
|
-
|
55
|
+
if attribute_type.is_a?(ActiveRecord::Type::Serialized)
|
56
|
+
value = attribute_type.serialize(value) unless value.is_a?(String)
|
53
57
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
"#{name}: |-\n#{value.to_s.indent(4)}" unless value.nil?
|
59
|
+
elsif value.is_a? LiveFixtures::Export::Reference
|
60
|
+
"#{value.name}: #{yml_value(value)}"
|
61
|
+
else
|
62
|
+
"#{name}: #{yml_value(value)}"
|
63
|
+
end
|
64
|
+
end
|
61
65
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
66
|
+
private_class_method def yml_value(value)
|
67
|
+
case value
|
68
|
+
when Time, DateTime
|
69
|
+
value.utc.to_fs(:db)
|
70
|
+
when Date
|
71
|
+
value.to_fs(:db)
|
72
|
+
when Hash
|
73
|
+
value.to_yaml.inspect
|
74
|
+
when String
|
75
|
+
value.inspect
|
76
|
+
when LiveFixtures::Export::Template
|
77
|
+
value.code
|
78
|
+
when LiveFixtures::Export::Reference
|
79
|
+
reference_value = value.value
|
80
|
+
"#{reference_value.class.table_name}_#{reference_value.id}"
|
81
|
+
else
|
82
|
+
value.to_s
|
83
|
+
end
|
84
|
+
end
|
79
85
|
end
|
80
86
|
end
|
81
87
|
end
|
data/lib/live_fixtures/export.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fileutils'
|
2
4
|
# This module is meant to be `include`ed into your export class.
|
3
5
|
#
|
@@ -8,100 +10,100 @@ require 'fileutils'
|
|
8
10
|
# one yml file for each db table. Do *not* call export_fixtures multiple
|
9
11
|
# times for the same db table - that will overwrite the file each time!
|
10
12
|
|
11
|
-
module LiveFixtures
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# References represent associations between fixtures, in the same way that foreign_keys do for records.
|
19
|
-
# These will be initialized for you based on the contents of `with_references` passed to `export_fixtures`.
|
20
|
-
# They will be initialized with the name of the association (a Symbol) and the particular associated model.
|
21
|
-
Reference = Struct.new(:name, :value)
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
# Specify the directory into which to export the yml files containing your fixtures.
|
26
|
-
# The directory will be created if it does not yet exist.
|
27
|
-
# @param dir [String] a path to a directory into which the fixtures will be exported.
|
28
|
-
def set_export_dir(dir)
|
29
|
-
@dir = dir
|
30
|
-
FileUtils.mkdir_p(@dir) unless File.directory?(@dir)
|
31
|
-
end
|
13
|
+
module LiveFixtures
|
14
|
+
module Export
|
15
|
+
# Templates allow you to export fixtures containing erb, that will be evaluated at the time of fixture import.
|
16
|
+
# You should initialize them with a String containing the erb to evaluate, like
|
17
|
+
# @example A template with export and import times.
|
18
|
+
# Template.new("<%= \"I was exported at #{Time.now} and imported at \" + Time.now.to_s %>")
|
19
|
+
Template = Struct.new(:code)
|
32
20
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
defaults = { show_progress: true }
|
38
|
-
@export_options = defaults.merge(opts)
|
39
|
-
end
|
21
|
+
# References represent associations between fixtures, in the same way that foreign_keys do for records.
|
22
|
+
# These will be initialized for you based on the contents of `with_references` passed to `export_fixtures`.
|
23
|
+
# They will be initialized with the name of the association (a Symbol) and the particular associated model.
|
24
|
+
Reference = Struct.new(:name, :value)
|
40
25
|
|
41
|
-
|
42
|
-
# @return [Hash] export configuration options
|
43
|
-
def export_options
|
44
|
-
@export_options ||= set_export_options
|
45
|
-
end
|
26
|
+
private
|
46
27
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
model_class = models.first.class
|
63
|
-
|
64
|
-
File.open(File.join(@dir, model_class.table_name + '.yml'), 'w') do |file|
|
65
|
-
file.write <<~PRELUDE
|
66
|
-
_fixture:
|
67
|
-
model_class: #{model_class.name}
|
68
|
-
PRELUDE
|
69
|
-
|
70
|
-
iterator = export_options[:show_progress] ? ProgressBarIterator : SimpleIterator
|
71
|
-
|
72
|
-
iterator.new(models).each do |model|
|
73
|
-
more_attributes = block_given? ? yield(model) : {}
|
74
|
-
file.write Fixture.to_yaml(model, with_references, more_attributes, skip_attributes: skip_attributes)
|
75
|
-
end
|
28
|
+
# Specify the directory into which to export the yml files containing your fixtures.
|
29
|
+
# The directory will be created if it does not yet exist.
|
30
|
+
# @param dir [String] a path to a directory into which the fixtures will be exported.
|
31
|
+
def set_export_dir(dir)
|
32
|
+
@dir = dir
|
33
|
+
FileUtils.mkdir_p(@dir) unless File.directory?(@dir)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Specify the options to use when exporting your fixtures.
|
37
|
+
# @param [Hash] opts export configuration options
|
38
|
+
# @option opts [Boolean] show_progress whether or not to show the progress bar
|
39
|
+
def set_export_options(**opts)
|
40
|
+
defaults = { show_progress: true }
|
41
|
+
@export_options = defaults.merge(opts)
|
76
42
|
end
|
77
|
-
end
|
78
43
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
@
|
83
|
-
total:models.size,
|
84
|
-
title: models.first.class.name
|
85
|
-
)
|
44
|
+
# The options to use when exporting your fixtures.
|
45
|
+
# @return [Hash] export configuration options
|
46
|
+
def export_options
|
47
|
+
@export_options ||= set_export_options
|
86
48
|
end
|
87
49
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
50
|
+
##
|
51
|
+
# Export models to a yml file named after the corresponding table.
|
52
|
+
# @param models [Enumerable] an Enumerable containing ActiveRecord models.
|
53
|
+
# @param with_references [Array<Symbol>] the associations whose foreign_keys should be replaced with references.
|
54
|
+
# @param skip_attributes [Array<String>] the attributes to skip when exporting the model.
|
55
|
+
#
|
56
|
+
# Takes an optional block that will be invoked for each model.
|
57
|
+
# The block should return a hash of attributes to be merged and
|
58
|
+
# saved with the model's attributes.
|
59
|
+
# @yield [model] an optional block that will be invoked for each model.
|
60
|
+
# @yieldparam model [ActiveRecord::Base] each successive model.
|
61
|
+
# @yieldreturn [Hash{String => Object}] a hash of attributes to be merged and saved with the model's attributes.
|
62
|
+
def export_fixtures(models, with_references = [], skip_attributes: [])
|
63
|
+
return [] unless models.present?
|
64
|
+
|
65
|
+
model_class = models.first.class
|
66
|
+
|
67
|
+
File.open(File.join(@dir, "#{model_class.table_name}.yml"), 'w') do |file|
|
68
|
+
file.write <<~PRELUDE
|
69
|
+
_fixture:
|
70
|
+
model_class: #{model_class.name}
|
71
|
+
PRELUDE
|
72
|
+
|
73
|
+
iterator = export_options[:show_progress] ? ProgressBarIterator : SimpleIterator
|
74
|
+
|
75
|
+
iterator.new(models).each do |model|
|
76
|
+
more_attributes = block_given? ? yield(model) : {}
|
77
|
+
file.write Fixture.to_yaml(model, with_references, more_attributes, skip_attributes: skip_attributes)
|
78
|
+
end
|
92
79
|
end
|
93
80
|
end
|
94
|
-
end
|
95
81
|
|
96
|
-
|
97
|
-
|
98
|
-
|
82
|
+
class ProgressBarIterator
|
83
|
+
def initialize(models)
|
84
|
+
@models = models
|
85
|
+
@bar = LiveFixtures.get_progress_bar(
|
86
|
+
total: models.size,
|
87
|
+
title: models.first.class.name
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
def each
|
92
|
+
@models.each do |model|
|
93
|
+
yield model
|
94
|
+
@bar.increment
|
95
|
+
end
|
96
|
+
end
|
99
97
|
end
|
100
98
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
99
|
+
class SimpleIterator
|
100
|
+
def initialize(models)
|
101
|
+
@models = models
|
102
|
+
end
|
103
|
+
|
104
|
+
def each(&)
|
105
|
+
puts @models.first.class.name
|
106
|
+
@models.each(&)
|
105
107
|
end
|
106
108
|
end
|
107
109
|
end
|
@@ -1,52 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_record/fixtures'
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
5
|
+
module LiveFixtures
|
6
|
+
class Import
|
7
|
+
# A labeled reference was not found.
|
8
|
+
# Maybe the referenced model was not exported, or the insert order attempted
|
9
|
+
# to import the reference before the referenced model?
|
10
|
+
LiveFixtures::MissingReferenceError = Class.new(KeyError)
|
11
|
+
|
12
|
+
class Fixtures
|
13
|
+
delegate :model_class, :table_name, :fixtures, to: :ar_fixtures
|
14
|
+
# ActiveRecord::FixtureSet for delegation
|
15
|
+
attr_reader :ar_fixtures
|
16
|
+
|
17
|
+
# @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter] connection to the database into which to import the data.
|
18
|
+
# @param table_name [String] name of the database table to populate with models
|
19
|
+
# @param class_name [Constant] the model's class name
|
20
|
+
# @param filepath [String] path to the yml file containing the fixtures
|
21
|
+
# @param label_to_id [Hash{String => Int}] map from a reference's label to its new id.
|
22
|
+
def initialize(connection, table_name, class_name, filepath, label_to_id, skip_missing_refs: false)
|
23
|
+
@skip_missing_refs = skip_missing_refs
|
24
|
+
@ar_fixtures = ActiveRecord::FixtureSet.new connection,
|
25
|
+
table_name,
|
26
|
+
class_name,
|
27
|
+
filepath
|
28
|
+
@label_to_id = label_to_id
|
29
|
+
end
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
# Rewritten to take advantage of @label_to_id instead of AR::FixtureSet#identify,
|
32
|
+
# and to make an iterator.
|
33
|
+
#
|
34
|
+
# @yieldparam table_name [String] the database table's name
|
35
|
+
# @yieldparam label [String] the label for the model being currently imported
|
36
|
+
# @yieldparam row [Hash{String => Value}] the model's attributes to be imported
|
37
|
+
# Iterator which yields [table_name, label, row] for each fixture
|
38
|
+
# (and for any implicit join table records). The block is expected to insert
|
39
|
+
# the row and update @label_to_id with the record's newly assigned id.
|
40
|
+
# @see https://github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/fixtures.rb#L611
|
41
|
+
def each_table_row_with_label
|
42
|
+
join_table_rows = Hash.new { |h, table| h[table] = [] }
|
40
43
|
|
41
|
-
|
42
|
-
|
44
|
+
fixtures.map do |label, fixture|
|
45
|
+
row = fixture.to_hash
|
43
46
|
|
44
|
-
|
47
|
+
reflection_class = reflection_class_for row
|
45
48
|
|
46
|
-
|
47
|
-
|
49
|
+
reflection_class.reflect_on_all_associations.each do |association|
|
50
|
+
next unless row[association.name.to_s]
|
48
51
|
|
49
|
-
|
52
|
+
case association.macro
|
50
53
|
when :belongs_to
|
51
54
|
maybe_convert_association_to_foreign_key row, association
|
52
55
|
|
@@ -59,77 +62,78 @@ class LiveFixtures::Import
|
|
59
62
|
join_table_rows[join_table_name] << { targets: targets,
|
60
63
|
association: association,
|
61
64
|
label: label }
|
65
|
+
end
|
62
66
|
end
|
63
|
-
end
|
64
67
|
|
65
|
-
|
66
|
-
|
68
|
+
yield [table_name, label, row]
|
69
|
+
end
|
67
70
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
join_table_rows.each do |table_name, rows|
|
72
|
+
rows.each do |row|
|
73
|
+
row[:targets].each do |target|
|
74
|
+
assoc_fk = @label_to_id[target] || target
|
75
|
+
row_with_fk = { row[:association].foreign_key => fetch_id_for_label(row[:label]),
|
76
|
+
row[:association].association_foreign_key => assoc_fk }
|
77
|
+
yield [table_name, NO_LABEL, row_with_fk]
|
78
|
+
end
|
75
79
|
end
|
76
80
|
end
|
77
81
|
end
|
78
|
-
end
|
79
82
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
+
def model_connection
|
84
|
+
model_class.connection if model_class.respond_to? :connection
|
85
|
+
end
|
83
86
|
|
84
|
-
|
87
|
+
private
|
85
88
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
+
def inheritance_column_name
|
90
|
+
@inheritance_column_name ||= model_class&.inheritance_column
|
91
|
+
end
|
89
92
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
+
# If STI is used, find the correct subclass for association reflection
|
94
|
+
def reflection_class_for(row)
|
95
|
+
return model_class unless row.include?(inheritance_column_name)
|
93
96
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
97
|
+
row[inheritance_column_name].constantize
|
98
|
+
rescue StandardError
|
99
|
+
model_class
|
100
|
+
end
|
98
101
|
|
99
|
-
|
100
|
-
|
102
|
+
def maybe_convert_association_to_foreign_key(row, association)
|
103
|
+
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
|
101
104
|
|
102
|
-
|
103
|
-
|
105
|
+
# Do not replace association name with association foreign key if they are named the same
|
106
|
+
return if association.name.to_s == fk_name
|
104
107
|
|
105
|
-
|
108
|
+
value = row.delete(association.name.to_s)
|
106
109
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
110
|
+
# support polymorphic belongs_to as "label (Type)"
|
111
|
+
row[association.foreign_type] = ::Regexp.last_match(1) if association.options[:polymorphic] && value.sub!(
|
112
|
+
/\s*\(([^\)]*)\)\s*$/, ''
|
113
|
+
)
|
111
114
|
|
112
|
-
|
113
|
-
|
115
|
+
row[fk_name] = fetch_id_for_label(value)
|
116
|
+
end
|
114
117
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
118
|
+
# Uses the underlying map of labels to return the referenced model's newly
|
119
|
+
# assigned ID.
|
120
|
+
# @raise [LiveFixtures::MissingReferenceError] if the label isn't found.
|
121
|
+
# @param label_to_fetch [String] the label of the referenced model.
|
122
|
+
# @return [Integer] the newly assigned ID of the referenced model.
|
123
|
+
def fetch_id_for_label(label_to_fetch)
|
124
|
+
@label_to_id.fetch(label_to_fetch)
|
125
|
+
rescue KeyError
|
126
|
+
return nil if @skip_missing_refs
|
127
|
+
|
128
|
+
raise LiveFixtures::MissingReferenceError, <<-ERROR.squish
|
126
129
|
Unable to find ID for model referenced by label #{label_to_fetch} while
|
127
130
|
importing #{model_class} from #{table_name}.yml. Perhaps it isn't included
|
128
131
|
in these fixtures or it is too late in the insert_order and has not yet
|
129
132
|
been imported.
|
130
|
-
|
131
|
-
|
133
|
+
ERROR
|
134
|
+
end
|
132
135
|
|
133
|
-
|
136
|
+
private :ar_fixtures
|
137
|
+
end
|
134
138
|
end
|
135
139
|
end
|