activerecord-import 0.23.0 → 1.4.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 +5 -5
- data/.github/workflows/test.yaml +107 -0
- data/.gitignore +1 -0
- data/CHANGELOG.md +214 -4
- data/Gemfile +11 -9
- data/LICENSE +21 -56
- data/README.markdown +574 -22
- data/Rakefile +2 -1
- data/activerecord-import.gemspec +4 -4
- data/benchmarks/benchmark.rb +5 -1
- data/benchmarks/schema/{mysql_schema.rb → mysql2_schema.rb} +0 -0
- data/gemfiles/5.0.gemfile +1 -0
- data/gemfiles/5.1.gemfile +1 -0
- data/gemfiles/5.2.gemfile +2 -2
- data/gemfiles/6.0.gemfile +2 -0
- data/gemfiles/6.1.gemfile +2 -0
- data/gemfiles/7.0.gemfile +1 -0
- data/lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb +4 -4
- data/lib/activerecord-import/adapters/abstract_adapter.rb +7 -1
- data/lib/activerecord-import/adapters/mysql_adapter.rb +8 -11
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +14 -16
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +125 -8
- data/lib/activerecord-import/base.rb +9 -1
- data/lib/activerecord-import/import.rb +269 -123
- data/lib/activerecord-import/synchronize.rb +2 -2
- data/lib/activerecord-import/value_sets_parser.rb +2 -0
- data/lib/activerecord-import/version.rb +1 -1
- data/lib/activerecord-import.rb +1 -0
- data/test/adapters/makara_postgis.rb +1 -0
- data/test/{travis → github}/database.yml +3 -1
- data/test/import_test.rb +138 -8
- data/test/makara_postgis/import_test.rb +8 -0
- data/test/models/animal.rb +6 -0
- data/test/models/card.rb +3 -0
- data/test/models/customer.rb +6 -0
- data/test/models/deck.rb +6 -0
- data/test/models/order.rb +6 -0
- data/test/models/playing_card.rb +2 -0
- data/test/models/user.rb +3 -1
- data/test/models/user_token.rb +4 -0
- data/test/schema/generic_schema.rb +30 -0
- data/test/schema/mysql2_schema.rb +19 -0
- data/test/schema/postgresql_schema.rb +16 -0
- data/test/schema/sqlite3_schema.rb +13 -0
- data/test/support/factories.rb +8 -8
- data/test/support/generate.rb +6 -6
- data/test/support/mysql/import_examples.rb +12 -0
- data/test/support/postgresql/import_examples.rb +100 -2
- data/test/support/shared_examples/on_duplicate_key_update.rb +54 -0
- data/test/support/shared_examples/recursive_import.rb +74 -4
- data/test/support/sqlite3/import_examples.rb +189 -25
- data/test/test_helper.rb +28 -3
- metadata +37 -18
- data/.travis.yml +0 -62
- data/gemfiles/3.2.gemfile +0 -2
- data/gemfiles/4.0.gemfile +0 -2
- data/gemfiles/4.1.gemfile +0 -2
- data/test/schema/mysql_schema.rb +0 -16
@@ -39,8 +39,8 @@ module ActiveRecord # :nodoc:
|
|
39
39
|
|
40
40
|
next unless matched_instance
|
41
41
|
|
42
|
-
instance.
|
43
|
-
instance.send :
|
42
|
+
instance.instance_variable_set :@association_cache, {}
|
43
|
+
instance.send :clear_aggregation_cache if instance.respond_to?(:clear_aggregation_cache, true)
|
44
44
|
instance.instance_variable_set :@attributes, matched_instance.instance_variable_get(:@attributes)
|
45
45
|
|
46
46
|
if instance.respond_to?(:clear_changes_information)
|
data/lib/activerecord-import.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
ENV["ARE_DB"] = "postgis"
|
@@ -1,7 +1,8 @@
|
|
1
1
|
common: &common
|
2
2
|
username: root
|
3
|
-
password:
|
3
|
+
password: root
|
4
4
|
encoding: utf8
|
5
|
+
collation: utf8_general_ci
|
5
6
|
host: localhost
|
6
7
|
database: activerecord_import_test
|
7
8
|
|
@@ -37,6 +38,7 @@ oracle:
|
|
37
38
|
postgresql: &postgresql
|
38
39
|
<<: *common
|
39
40
|
username: postgres
|
41
|
+
password: postgres
|
40
42
|
adapter: postgresql
|
41
43
|
min_messages: warning
|
42
44
|
|
data/test/import_test.rb
CHANGED
@@ -17,6 +17,11 @@ describe "#import" do
|
|
17
17
|
assert_equal error.message, "Last argument should be a two dimensional array '[[]]'. First element in array was a String"
|
18
18
|
end
|
19
19
|
|
20
|
+
it "warns you that you're passing more data than you ought to" do
|
21
|
+
error = assert_raise(ArgumentError) { Topic.import %w(title author_name), [['Author #1', 'Book #1', 0]] }
|
22
|
+
assert_equal error.message, "Number of values (8) exceeds number of columns (7)"
|
23
|
+
end
|
24
|
+
|
20
25
|
it "should not produce an error when importing empty arrays" do
|
21
26
|
assert_nothing_raised do
|
22
27
|
Topic.import []
|
@@ -164,7 +169,17 @@ describe "#import" do
|
|
164
169
|
assert_difference "Dictionary.count", +1 do
|
165
170
|
Dictionary.import dictionaries
|
166
171
|
end
|
167
|
-
assert_equal "Dictionary", Dictionary.
|
172
|
+
assert_equal "Dictionary", Dictionary.last.type
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should import arrays successfully" do
|
176
|
+
columns = [:author_name, :title]
|
177
|
+
values = [["Noah Webster", "Webster's Dictionary"]]
|
178
|
+
|
179
|
+
assert_difference "Dictionary.count", +1 do
|
180
|
+
Dictionary.import columns, values
|
181
|
+
end
|
182
|
+
assert_equal "Dictionary", Dictionary.last.type
|
168
183
|
end
|
169
184
|
end
|
170
185
|
|
@@ -210,9 +225,9 @@ describe "#import" do
|
|
210
225
|
end
|
211
226
|
|
212
227
|
it "should ignore uniqueness validators" do
|
213
|
-
Topic.import columns, valid_values
|
228
|
+
Topic.import columns, valid_values
|
214
229
|
assert_difference "Topic.count", +2 do
|
215
|
-
Topic.import columns, valid_values
|
230
|
+
Topic.import columns, valid_values
|
216
231
|
end
|
217
232
|
end
|
218
233
|
|
@@ -247,6 +262,16 @@ describe "#import" do
|
|
247
262
|
end
|
248
263
|
end
|
249
264
|
|
265
|
+
it "should index the failed instances by their poistion in the set if `track_failures` is true" do
|
266
|
+
index_offset = valid_values.length
|
267
|
+
results = Topic.import columns, valid_values + invalid_values, validate: true, track_validation_failures: true
|
268
|
+
assert_equal invalid_values.size, results.failed_instances.size
|
269
|
+
invalid_values.each_with_index do |value_set, index|
|
270
|
+
assert_equal index + index_offset, results.failed_instances[index].first
|
271
|
+
assert_equal value_set.first, results.failed_instances[index].last.title
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
250
275
|
it "should set ids in valid models if adapter supports setting primary key of imported objects" do
|
251
276
|
if ActiveRecord::Base.supports_setting_primary_key_of_imported_objects?
|
252
277
|
Topic.import (invalid_models + valid_models), validate: true
|
@@ -294,6 +319,36 @@ describe "#import" do
|
|
294
319
|
end
|
295
320
|
end
|
296
321
|
end
|
322
|
+
|
323
|
+
context "with uniqueness validators included" do
|
324
|
+
it "should not import duplicate records" do
|
325
|
+
Topic.import columns, valid_values
|
326
|
+
assert_no_difference "Topic.count" do
|
327
|
+
Topic.import columns, valid_values, validate_uniqueness: true
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
context "when validatoring presence of belongs_to association" do
|
333
|
+
it "should not import records without foreign key" do
|
334
|
+
assert_no_difference "UserToken.count" do
|
335
|
+
UserToken.import [:token], [['12345abcdef67890']]
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
it "should import records with foreign key" do
|
340
|
+
assert_difference "UserToken.count", +1 do
|
341
|
+
UserToken.import [:user_name, :token], [%w("Bob", "12345abcdef67890")]
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
it "should not mutate the defined validations" do
|
346
|
+
UserToken.import [:user_name, :token], [%w("Bob", "12345abcdef67890")]
|
347
|
+
ut = UserToken.new
|
348
|
+
ut.valid?
|
349
|
+
assert_includes ut.errors.messages, :user
|
350
|
+
end
|
351
|
+
end
|
297
352
|
end
|
298
353
|
|
299
354
|
context "without :validation option" do
|
@@ -360,6 +415,15 @@ describe "#import" do
|
|
360
415
|
assert_equal 3, result.num_inserts if Topic.supports_import?
|
361
416
|
end
|
362
417
|
end
|
418
|
+
|
419
|
+
it "should accept and call an optional callable to run after each batch" do
|
420
|
+
lambda_called = 0
|
421
|
+
|
422
|
+
my_proc = ->(_row_count, _batches, _batch, _duration) { lambda_called += 1 }
|
423
|
+
Topic.import Build(10, :topics), batch_size: 4, batch_progress: my_proc
|
424
|
+
|
425
|
+
assert_equal 3, lambda_called
|
426
|
+
end
|
363
427
|
end
|
364
428
|
|
365
429
|
context "with :synchronize option" do
|
@@ -490,11 +554,15 @@ describe "#import" do
|
|
490
554
|
|
491
555
|
context "when the timestamps columns are present" do
|
492
556
|
setup do
|
493
|
-
@existing_book = Book.create(title: "Fell", author_name: "Curry", publisher: "Bayer", created_at: 2.years.ago.utc, created_on: 2.years.ago.utc)
|
494
|
-
ActiveRecord
|
557
|
+
@existing_book = Book.create(title: "Fell", author_name: "Curry", publisher: "Bayer", created_at: 2.years.ago.utc, created_on: 2.years.ago.utc, updated_at: 2.years.ago.utc, updated_on: 2.years.ago.utc)
|
558
|
+
if ActiveRecord.respond_to?(:default_timezone)
|
559
|
+
ActiveRecord.default_timezone = :utc
|
560
|
+
else
|
561
|
+
ActiveRecord::Base.default_timezone = :utc
|
562
|
+
end
|
495
563
|
Timecop.freeze(time) do
|
496
564
|
assert_difference "Book.count", +2 do
|
497
|
-
Book.import %w(title author_name publisher created_at created_on), [["LDAP", "Big Bird", "Del Rey", nil, nil], [@existing_book.title, @existing_book.author_name, @existing_book.publisher, @existing_book.created_at, @existing_book.created_on]]
|
565
|
+
Book.import %w(title author_name publisher created_at created_on updated_at updated_on), [["LDAP", "Big Bird", "Del Rey", nil, nil, nil, nil], [@existing_book.title, @existing_book.author_name, @existing_book.publisher, @existing_book.created_at, @existing_book.created_on, @existing_book.updated_at, @existing_book.updated_on]]
|
498
566
|
end
|
499
567
|
end
|
500
568
|
@new_book, @existing_book = Book.last 2
|
@@ -523,6 +591,23 @@ describe "#import" do
|
|
523
591
|
it "should set the updated_on column for new records" do
|
524
592
|
assert_in_delta time.to_i, @new_book.updated_on.to_i, 1.second
|
525
593
|
end
|
594
|
+
|
595
|
+
it "should not set the updated_at column for existing records" do
|
596
|
+
assert_equal 2.years.ago.utc.strftime("%Y:%d"), @existing_book.updated_at.strftime("%Y:%d")
|
597
|
+
end
|
598
|
+
|
599
|
+
it "should not set the updated_on column for existing records" do
|
600
|
+
assert_equal 2.years.ago.utc.strftime("%Y:%d"), @existing_book.updated_on.strftime("%Y:%d")
|
601
|
+
end
|
602
|
+
|
603
|
+
it "should not set the updated_at column on models if changed" do
|
604
|
+
timestamp = Time.now.utc
|
605
|
+
books = [
|
606
|
+
Book.new(author_name: "Foo", title: "Baz", created_at: timestamp, updated_at: timestamp)
|
607
|
+
]
|
608
|
+
Book.import books
|
609
|
+
assert_equal timestamp.strftime("%Y:%d"), Book.last.updated_at.strftime("%Y:%d")
|
610
|
+
end
|
526
611
|
end
|
527
612
|
|
528
613
|
context "when a custom time zone is set" do
|
@@ -567,7 +652,7 @@ describe "#import" do
|
|
567
652
|
|
568
653
|
context "importing through an association scope" do
|
569
654
|
{ has_many: :chapters, polymorphic: :discounts }.each do |association_type, association|
|
570
|
-
book =
|
655
|
+
book = FactoryBot.create :book
|
571
656
|
scope = book.public_send association
|
572
657
|
klass = { chapters: Chapter, discounts: Discount }[association]
|
573
658
|
column = { chapters: :title, discounts: :amount }[association]
|
@@ -590,18 +675,34 @@ describe "#import" do
|
|
590
675
|
assert_equal [val1, val2], scope.map(&column).sort
|
591
676
|
end
|
592
677
|
|
678
|
+
context "for cards and decks" do
|
679
|
+
it "works when the polymorphic name is different than base class name" do
|
680
|
+
deck = Deck.create(id: 1, name: 'test')
|
681
|
+
deck.cards.import [:id, :deck_type], [[1, 'PlayingCard']]
|
682
|
+
assert_equal deck.cards.first.deck_type, "PlayingCard"
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
593
686
|
it "works importing array of hashes" do
|
594
687
|
scope.import [{ column => val1 }, { column => val2 }]
|
595
688
|
|
596
689
|
assert_equal [val1, val2], scope.map(&column).sort
|
597
690
|
end
|
598
691
|
end
|
692
|
+
|
693
|
+
it "works with a non-standard association primary key" do
|
694
|
+
user = User.create(id: 1, name: 'Solomon')
|
695
|
+
user.user_tokens.import [:id, :token], [[5, '12345abcdef67890']]
|
696
|
+
|
697
|
+
token = UserToken.find(5)
|
698
|
+
assert_equal 'Solomon', token.user_name
|
699
|
+
end
|
599
700
|
end
|
600
701
|
end
|
601
702
|
|
602
703
|
context "importing model with polymorphic belongs_to" do
|
603
704
|
it "works without error" do
|
604
|
-
book =
|
705
|
+
book = FactoryBot.create :book
|
605
706
|
discount = Discount.new(discountable: book)
|
606
707
|
|
607
708
|
Discount.import([discount])
|
@@ -840,4 +941,33 @@ describe "#import" do
|
|
840
941
|
end
|
841
942
|
end
|
842
943
|
end
|
944
|
+
describe "importing model with after_initialize callback" do
|
945
|
+
let(:columns) { %w(name size) }
|
946
|
+
let(:valid_values) { [%w("Deer", "Small"), %w("Monkey", "Medium")] }
|
947
|
+
let(:invalid_values) do
|
948
|
+
[
|
949
|
+
{ name: "giraffe", size: "Large" },
|
950
|
+
{ size: "Medium" } # name is missing
|
951
|
+
]
|
952
|
+
end
|
953
|
+
context "with validation checks turned off" do
|
954
|
+
it "should import valid data" do
|
955
|
+
Animal.import(columns, valid_values, validate: false)
|
956
|
+
assert_equal 2, Animal.count
|
957
|
+
end
|
958
|
+
it "should raise ArgumentError" do
|
959
|
+
assert_raise(ArgumentError) { Animal.import(invalid_values, validate: false) }
|
960
|
+
end
|
961
|
+
end
|
962
|
+
|
963
|
+
context "with validation checks turned on" do
|
964
|
+
it "should import valid data" do
|
965
|
+
Animal.import(columns, valid_values, validate: true)
|
966
|
+
assert_equal 2, Animal.count
|
967
|
+
end
|
968
|
+
it "should raise ArgumentError" do
|
969
|
+
assert_raise(ArgumentError) { Animal.import(invalid_values, validate: true) }
|
970
|
+
end
|
971
|
+
end
|
972
|
+
end
|
843
973
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
|
3
|
+
|
4
|
+
should_support_postgresql_import_functionality
|
5
|
+
|
6
|
+
if ActiveRecord::Base.connection.supports_on_duplicate_key_update?
|
7
|
+
should_support_postgresql_upsert_functionality
|
8
|
+
end
|
data/test/models/card.rb
ADDED
data/test/models/deck.rb
ADDED
data/test/models/user.rb
CHANGED
@@ -52,6 +52,20 @@ ActiveRecord::Schema.define do
|
|
52
52
|
t.string :name
|
53
53
|
end
|
54
54
|
|
55
|
+
create_table :cards, force: :cascade do |t|
|
56
|
+
t.string :name
|
57
|
+
t.string :deck_type
|
58
|
+
t.integer :deck_id
|
59
|
+
end
|
60
|
+
|
61
|
+
create_table :decks, force: :cascade do |t|
|
62
|
+
t.string :name
|
63
|
+
end
|
64
|
+
|
65
|
+
create_table :playing_cards, force: :cascade do |t|
|
66
|
+
t.string :name
|
67
|
+
end
|
68
|
+
|
55
69
|
create_table :books, force: :cascade do |t|
|
56
70
|
t.string :title, null: false
|
57
71
|
t.string :publisher, null: false, default: 'Default Publisher'
|
@@ -164,6 +178,11 @@ ActiveRecord::Schema.define do
|
|
164
178
|
t.integer :lock_version, null: false, default: 0
|
165
179
|
end
|
166
180
|
|
181
|
+
create_table :user_tokens, force: :cascade do |t|
|
182
|
+
t.string :user_name, null: false
|
183
|
+
t.string :token, null: false
|
184
|
+
end
|
185
|
+
|
167
186
|
create_table :accounts, force: :cascade do |t|
|
168
187
|
t.string :name, null: false
|
169
188
|
t.integer :lock, null: false, default: 0
|
@@ -186,4 +205,15 @@ ActiveRecord::Schema.define do
|
|
186
205
|
);
|
187
206
|
).split.join(' ').strip
|
188
207
|
end
|
208
|
+
|
209
|
+
create_table :customers, force: :cascade do |t|
|
210
|
+
t.integer :account_id
|
211
|
+
t.string :name
|
212
|
+
end
|
213
|
+
|
214
|
+
create_table :orders, force: :cascade do |t|
|
215
|
+
t.integer :account_id
|
216
|
+
t.integer :customer_id
|
217
|
+
t.integer :amount
|
218
|
+
end
|
189
219
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
create_table :books, force: :cascade do |t|
|
3
|
+
t.string :title, null: false
|
4
|
+
t.virtual :upper_title, type: :string, as: "upper(`title`)" if t.respond_to?(:virtual)
|
5
|
+
t.string :publisher, null: false, default: 'Default Publisher'
|
6
|
+
t.string :author_name, null: false
|
7
|
+
t.datetime :created_at
|
8
|
+
t.datetime :created_on
|
9
|
+
t.datetime :updated_at
|
10
|
+
t.datetime :updated_on
|
11
|
+
t.date :publish_date
|
12
|
+
t.integer :topic_id
|
13
|
+
t.integer :tag_id
|
14
|
+
t.integer :publisher_id
|
15
|
+
t.boolean :for_sale, default: true
|
16
|
+
t.integer :status, default: 0
|
17
|
+
t.string :type
|
18
|
+
end
|
19
|
+
end
|
@@ -3,11 +3,24 @@ ActiveRecord::Schema.define do
|
|
3
3
|
execute('CREATE extension IF NOT EXISTS "pgcrypto";')
|
4
4
|
execute('CREATE extension IF NOT EXISTS "uuid-ossp";')
|
5
5
|
|
6
|
+
# create ENUM if it does not exist yet
|
7
|
+
begin
|
8
|
+
execute('CREATE TYPE vendor_type AS ENUM (\'wholesaler\', \'retailer\');')
|
9
|
+
rescue ActiveRecord::StatementInvalid => e
|
10
|
+
# since PostgreSQL does not support IF NOT EXISTS when creating a TYPE,
|
11
|
+
# rescue the error and check the error class
|
12
|
+
raise unless e.cause.is_a? PG::DuplicateObject
|
13
|
+
execute('ALTER TYPE vendor_type ADD VALUE IF NOT EXISTS \'wholesaler\';')
|
14
|
+
execute('ALTER TYPE vendor_type ADD VALUE IF NOT EXISTS \'retailer\';')
|
15
|
+
end
|
16
|
+
|
6
17
|
create_table :vendors, id: :uuid, force: :cascade do |t|
|
7
18
|
t.string :name, null: true
|
19
|
+
t.text :hours
|
8
20
|
t.text :preferences
|
9
21
|
|
10
22
|
if t.respond_to?(:json)
|
23
|
+
t.json :pure_json_data
|
11
24
|
t.json :data
|
12
25
|
else
|
13
26
|
t.text :data
|
@@ -20,6 +33,7 @@ ActiveRecord::Schema.define do
|
|
20
33
|
end
|
21
34
|
|
22
35
|
if t.respond_to?(:jsonb)
|
36
|
+
t.jsonb :pure_jsonb_data
|
23
37
|
t.jsonb :settings
|
24
38
|
t.jsonb :json_data, null: false, default: {}
|
25
39
|
else
|
@@ -27,6 +41,8 @@ ActiveRecord::Schema.define do
|
|
27
41
|
t.text :json_data
|
28
42
|
end
|
29
43
|
|
44
|
+
t.column :vendor_type, :vendor_type
|
45
|
+
|
30
46
|
t.datetime :created_at
|
31
47
|
t.datetime :updated_at
|
32
48
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
create_table :alarms, force: true do |t|
|
3
|
+
t.column :device_id, :integer, null: false
|
4
|
+
t.column :alarm_type, :integer, null: false
|
5
|
+
t.column :status, :integer, null: false
|
6
|
+
t.column :metadata, :text
|
7
|
+
t.column :secret_key, :binary
|
8
|
+
t.datetime :created_at
|
9
|
+
t.datetime :updated_at
|
10
|
+
end
|
11
|
+
|
12
|
+
add_index :alarms, [:device_id, :alarm_type], unique: true, where: 'status <> 0'
|
13
|
+
end
|
data/test/support/factories.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
FactoryBot.define do
|
2
2
|
sequence(:book_title) { |n| "Book #{n}" }
|
3
3
|
sequence(:chapter_title) { |n| "Chapter #{n}" }
|
4
4
|
sequence(:end_note) { |n| "Endnote #{n}" }
|
@@ -9,7 +9,7 @@ FactoryGirl.define do
|
|
9
9
|
|
10
10
|
factory :invalid_topic, class: "Topic" do
|
11
11
|
sequence(:title) { |n| "Title #{n}" }
|
12
|
-
author_name nil
|
12
|
+
author_name { nil }
|
13
13
|
end
|
14
14
|
|
15
15
|
factory :topic do
|
@@ -27,7 +27,7 @@ FactoryGirl.define do
|
|
27
27
|
|
28
28
|
trait :with_rule do
|
29
29
|
after(:build) do |question|
|
30
|
-
question.build_rule(
|
30
|
+
question.build_rule(FactoryBot.attributes_for(:rule))
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -40,21 +40,21 @@ FactoryGirl.define do
|
|
40
40
|
factory :topic_with_book, parent: :topic do
|
41
41
|
after(:build) do |topic|
|
42
42
|
2.times do
|
43
|
-
book = topic.books.build(title:
|
43
|
+
book = topic.books.build(title: FactoryBot.generate(:book_title), author_name: 'Stephen King')
|
44
44
|
3.times do
|
45
|
-
book.chapters.build(title:
|
45
|
+
book.chapters.build(title: FactoryBot.generate(:chapter_title))
|
46
46
|
end
|
47
47
|
|
48
48
|
4.times do
|
49
|
-
book.end_notes.build(note:
|
49
|
+
book.end_notes.build(note: FactoryBot.generate(:end_note))
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
55
|
factory :book do
|
56
|
-
title 'Tortilla Flat'
|
57
|
-
author_name 'John Steinbeck'
|
56
|
+
title { 'Tortilla Flat' }
|
57
|
+
author_name { 'John Steinbeck' }
|
58
58
|
end
|
59
59
|
|
60
60
|
factory :car do
|
data/test/support/generate.rb
CHANGED
@@ -2,28 +2,28 @@ class ActiveSupport::TestCase
|
|
2
2
|
def Build(*args) # rubocop:disable Style/MethodName
|
3
3
|
n = args.shift if args.first.is_a?(Numeric)
|
4
4
|
factory = args.shift
|
5
|
-
|
5
|
+
factory_bot_args = args.shift || {}
|
6
6
|
|
7
7
|
if n
|
8
8
|
[].tap do |collection|
|
9
|
-
n.times.each { collection <<
|
9
|
+
n.times.each { collection << FactoryBot.build(factory.to_s.singularize.to_sym, factory_bot_args) }
|
10
10
|
end
|
11
11
|
else
|
12
|
-
|
12
|
+
FactoryBot.build(factory.to_s.singularize.to_sym, factory_bot_args)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
def Generate(*args) # rubocop:disable Style/MethodName
|
17
17
|
n = args.shift if args.first.is_a?(Numeric)
|
18
18
|
factory = args.shift
|
19
|
-
|
19
|
+
factory_bot_args = args.shift || {}
|
20
20
|
|
21
21
|
if n
|
22
22
|
[].tap do |collection|
|
23
|
-
n.times.each { collection <<
|
23
|
+
n.times.each { collection << FactoryBot.create(factory.to_s.singularize.to_sym, factory_bot_args) }
|
24
24
|
end
|
25
25
|
else
|
26
|
-
|
26
|
+
FactoryBot.create(factory.to_s.singularize.to_sym, factory_bot_args)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -82,5 +82,17 @@ def should_support_mysql_import_functionality
|
|
82
82
|
assert_equal "Chad Fowler", topics.last.author_name, "wrong author!"
|
83
83
|
end
|
84
84
|
end
|
85
|
+
|
86
|
+
if ENV['AR_VERSION'].to_f >= 5.1
|
87
|
+
context "with virtual columns" do
|
88
|
+
let(:books) { [Book.new(author_name: "foo", title: "bar")] }
|
89
|
+
|
90
|
+
it "ignores virtual columns and creates record" do
|
91
|
+
assert_difference "Book.count", +1 do
|
92
|
+
Book.import books
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
85
97
|
end
|
86
98
|
end
|