activerecord-import 0.23.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yaml +107 -0
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +214 -4
  5. data/Gemfile +11 -9
  6. data/LICENSE +21 -56
  7. data/README.markdown +574 -22
  8. data/Rakefile +2 -1
  9. data/activerecord-import.gemspec +4 -4
  10. data/benchmarks/benchmark.rb +5 -1
  11. data/benchmarks/schema/{mysql_schema.rb → mysql2_schema.rb} +0 -0
  12. data/gemfiles/5.0.gemfile +1 -0
  13. data/gemfiles/5.1.gemfile +1 -0
  14. data/gemfiles/5.2.gemfile +2 -2
  15. data/gemfiles/6.0.gemfile +2 -0
  16. data/gemfiles/6.1.gemfile +2 -0
  17. data/gemfiles/7.0.gemfile +1 -0
  18. data/lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb +4 -4
  19. data/lib/activerecord-import/adapters/abstract_adapter.rb +7 -1
  20. data/lib/activerecord-import/adapters/mysql_adapter.rb +8 -11
  21. data/lib/activerecord-import/adapters/postgresql_adapter.rb +14 -16
  22. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +125 -8
  23. data/lib/activerecord-import/base.rb +9 -1
  24. data/lib/activerecord-import/import.rb +269 -123
  25. data/lib/activerecord-import/synchronize.rb +2 -2
  26. data/lib/activerecord-import/value_sets_parser.rb +2 -0
  27. data/lib/activerecord-import/version.rb +1 -1
  28. data/lib/activerecord-import.rb +1 -0
  29. data/test/adapters/makara_postgis.rb +1 -0
  30. data/test/{travis → github}/database.yml +3 -1
  31. data/test/import_test.rb +138 -8
  32. data/test/makara_postgis/import_test.rb +8 -0
  33. data/test/models/animal.rb +6 -0
  34. data/test/models/card.rb +3 -0
  35. data/test/models/customer.rb +6 -0
  36. data/test/models/deck.rb +6 -0
  37. data/test/models/order.rb +6 -0
  38. data/test/models/playing_card.rb +2 -0
  39. data/test/models/user.rb +3 -1
  40. data/test/models/user_token.rb +4 -0
  41. data/test/schema/generic_schema.rb +30 -0
  42. data/test/schema/mysql2_schema.rb +19 -0
  43. data/test/schema/postgresql_schema.rb +16 -0
  44. data/test/schema/sqlite3_schema.rb +13 -0
  45. data/test/support/factories.rb +8 -8
  46. data/test/support/generate.rb +6 -6
  47. data/test/support/mysql/import_examples.rb +12 -0
  48. data/test/support/postgresql/import_examples.rb +100 -2
  49. data/test/support/shared_examples/on_duplicate_key_update.rb +54 -0
  50. data/test/support/shared_examples/recursive_import.rb +74 -4
  51. data/test/support/sqlite3/import_examples.rb +189 -25
  52. data/test/test_helper.rb +28 -3
  53. metadata +37 -18
  54. data/.travis.yml +0 -62
  55. data/gemfiles/3.2.gemfile +0 -2
  56. data/gemfiles/4.0.gemfile +0 -2
  57. data/gemfiles/4.1.gemfile +0 -2
  58. 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.send :clear_aggregation_cache
43
- instance.send :clear_association_cache
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)
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/array'
2
+
1
3
  module ActiveRecord::Import
2
4
  class ValueSetTooLargeError < StandardError
3
5
  attr_reader :size
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Import
3
- VERSION = "0.23.0".freeze
3
+ VERSION = "1.4.0".freeze
4
4
  end
5
5
  end
@@ -1,4 +1,5 @@
1
1
  # rubocop:disable Style/FileName
2
+ require "active_support/lazy_load_hooks"
2
3
 
3
4
  ActiveSupport.on_load(:active_record) do
4
5
  require "activerecord-import/base"
@@ -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.first.type
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, validate: true
228
+ Topic.import columns, valid_values
214
229
  assert_difference "Topic.count", +2 do
215
- Topic.import columns, valid_values, validate: true
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::Base.default_timezone = :utc
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 = FactoryGirl.create :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 = FactoryGirl.create :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
@@ -0,0 +1,6 @@
1
+ class Animal < ActiveRecord::Base
2
+ after_initialize :validate_name_presence, if: :new_record?
3
+ def validate_name_presence
4
+ raise ArgumentError if name.nil?
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ class Card < ActiveRecord::Base
2
+ belongs_to :deck, polymorphic: true
3
+ end
@@ -0,0 +1,6 @@
1
+ class Customer < ActiveRecord::Base
2
+ has_many :orders,
3
+ inverse_of: :customer,
4
+ primary_key: %i(account_id id),
5
+ foreign_key: %i(account_id customer_id)
6
+ end
@@ -0,0 +1,6 @@
1
+ class Deck < ActiveRecord::Base
2
+ has_many :cards
3
+ def self.polymorphic_name
4
+ "PlayingCard"
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class Order < ActiveRecord::Base
2
+ belongs_to :customer,
3
+ inverse_of: :orders,
4
+ primary_key: %i(account_id id),
5
+ foreign_key: %i(account_id customer_id)
6
+ end
@@ -0,0 +1,2 @@
1
+ class PlayingCard < ActiveRecord::Base
2
+ end
data/test/models/user.rb CHANGED
@@ -1 +1,3 @@
1
- class User < ActiveRecord::Base; end
1
+ class User < ActiveRecord::Base
2
+ has_many :user_tokens, primary_key: :name, foreign_key: :user_name
3
+ end
@@ -0,0 +1,4 @@
1
+ class UserToken < ActiveRecord::Base
2
+ belongs_to :user, primary_key: :name, foreign_key: :user_name
3
+ validates :user, presence: true
4
+ end
@@ -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
@@ -1,4 +1,4 @@
1
- FactoryGirl.define do
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(FactoryGirl.attributes_for(: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: FactoryGirl.generate(:book_title), author_name: 'Stephen King')
43
+ book = topic.books.build(title: FactoryBot.generate(:book_title), author_name: 'Stephen King')
44
44
  3.times do
45
- book.chapters.build(title: FactoryGirl.generate(:chapter_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: FactoryGirl.generate(:end_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
@@ -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
- factory_girl_args = args.shift || {}
5
+ factory_bot_args = args.shift || {}
6
6
 
7
7
  if n
8
8
  [].tap do |collection|
9
- n.times.each { collection << FactoryGirl.build(factory.to_s.singularize.to_sym, factory_girl_args) }
9
+ n.times.each { collection << FactoryBot.build(factory.to_s.singularize.to_sym, factory_bot_args) }
10
10
  end
11
11
  else
12
- FactoryGirl.build(factory.to_s.singularize.to_sym, factory_girl_args)
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
- factory_girl_args = args.shift || {}
19
+ factory_bot_args = args.shift || {}
20
20
 
21
21
  if n
22
22
  [].tap do |collection|
23
- n.times.each { collection << FactoryGirl.create(factory.to_s.singularize.to_sym, factory_girl_args) }
23
+ n.times.each { collection << FactoryBot.create(factory.to_s.singularize.to_sym, factory_bot_args) }
24
24
  end
25
25
  else
26
- FactoryGirl.create(factory.to_s.singularize.to_sym, factory_girl_args)
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