activerecord-import 0.19.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +22 -12
  3. data/CHANGELOG.md +166 -0
  4. data/Gemfile +13 -10
  5. data/README.markdown +548 -5
  6. data/Rakefile +2 -1
  7. data/benchmarks/lib/cli_parser.rb +2 -1
  8. data/gemfiles/5.1.gemfile +1 -0
  9. data/gemfiles/5.2.gemfile +2 -0
  10. data/lib/activerecord-import/adapters/abstract_adapter.rb +2 -2
  11. data/lib/activerecord-import/adapters/mysql_adapter.rb +16 -10
  12. data/lib/activerecord-import/adapters/postgresql_adapter.rb +59 -15
  13. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +126 -3
  14. data/lib/activerecord-import/base.rb +4 -6
  15. data/lib/activerecord-import/import.rb +384 -126
  16. data/lib/activerecord-import/synchronize.rb +1 -1
  17. data/lib/activerecord-import/value_sets_parser.rb +14 -0
  18. data/lib/activerecord-import/version.rb +1 -1
  19. data/lib/activerecord-import.rb +2 -15
  20. data/test/adapters/makara_postgis.rb +1 -0
  21. data/test/import_test.rb +148 -14
  22. data/test/makara_postgis/import_test.rb +8 -0
  23. data/test/models/account.rb +3 -0
  24. data/test/models/bike_maker.rb +7 -0
  25. data/test/models/topic.rb +10 -0
  26. data/test/models/user.rb +3 -0
  27. data/test/models/user_token.rb +4 -0
  28. data/test/schema/generic_schema.rb +20 -0
  29. data/test/schema/mysql2_schema.rb +19 -0
  30. data/test/schema/postgresql_schema.rb +1 -0
  31. data/test/schema/sqlite3_schema.rb +13 -0
  32. data/test/support/factories.rb +9 -8
  33. data/test/support/generate.rb +6 -6
  34. data/test/support/mysql/import_examples.rb +14 -2
  35. data/test/support/postgresql/import_examples.rb +142 -0
  36. data/test/support/shared_examples/on_duplicate_key_update.rb +252 -1
  37. data/test/support/shared_examples/recursive_import.rb +41 -11
  38. data/test/support/sqlite3/import_examples.rb +187 -10
  39. data/test/synchronize_test.rb +8 -0
  40. data/test/test_helper.rb +9 -1
  41. data/test/value_sets_bytes_parser_test.rb +13 -2
  42. metadata +20 -5
  43. data/test/schema/mysql_schema.rb +0 -16
@@ -31,7 +31,7 @@ module ActiveRecord # :nodoc:
31
31
 
32
32
  klass = instances.first.class
33
33
 
34
- fresh_instances = klass.where(conditions).order(order)
34
+ fresh_instances = klass.unscoped.where(conditions).order(order)
35
35
  instances.each do |instance|
36
36
  matched_instance = fresh_instances.detect do |fresh_instance|
37
37
  keys.all? { |key| fresh_instance.send(key) == instance.send(key) }
@@ -1,4 +1,12 @@
1
1
  module ActiveRecord::Import
2
+ class ValueSetTooLargeError < StandardError
3
+ attr_reader :size
4
+ def initialize(msg = "Value set exceeds max size", size = 0)
5
+ @size = size
6
+ super(msg)
7
+ end
8
+ end
9
+
2
10
  class ValueSetsBytesParser
3
11
  attr_reader :reserved_bytes, :max_bytes, :values
4
12
 
@@ -18,6 +26,12 @@ module ActiveRecord::Import
18
26
  current_size = 0
19
27
  values.each_with_index do |val, i|
20
28
  comma_bytes = arr.size
29
+ insert_size = reserved_bytes + val.bytesize
30
+
31
+ if insert_size > max_bytes
32
+ raise ValueSetTooLargeError.new("#{insert_size} bytes exceeds the max allowed for an insert [#{@max_bytes}]", insert_size)
33
+ end
34
+
21
35
  bytes_thus_far = reserved_bytes + current_size + val.bytesize + comma_bytes
22
36
  if bytes_thus_far <= max_bytes
23
37
  current_size += val.bytesize
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Import
3
- VERSION = "0.19.0".freeze
3
+ VERSION = "1.0.0".freeze
4
4
  end
5
5
  end
@@ -1,19 +1,6 @@
1
1
  # rubocop:disable Style/FileName
2
+ require "active_support/lazy_load_hooks"
2
3
 
3
4
  ActiveSupport.on_load(:active_record) do
4
- class ActiveRecord::Base
5
- class << self
6
- def establish_connection_with_activerecord_import(*args)
7
- conn = establish_connection_without_activerecord_import(*args)
8
- if !ActiveRecord.const_defined?(:Import) || !ActiveRecord::Import.respond_to?(:load_from_connection_pool)
9
- require "activerecord-import/base"
10
- end
11
-
12
- ActiveRecord::Import.load_from_connection_pool connection_pool
13
- conn
14
- end
15
- alias establish_connection_without_activerecord_import establish_connection
16
- alias establish_connection establish_connection_with_activerecord_import
17
- end
18
- end
5
+ require "activerecord-import/base"
19
6
  end
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "postgis"
data/test/import_test.rb CHANGED
@@ -86,6 +86,54 @@ describe "#import" do
86
86
  assert_nil t.author_email_address
87
87
  end
88
88
  end
89
+
90
+ context "with extra keys" do
91
+ let(:values) do
92
+ [
93
+ { title: "LDAP", author_name: "Jerry Carter" },
94
+ { title: "Rails Recipes", author_name: "Chad Fowler", author_email_address: "cfowler@test.com" } # author_email_address is unknown
95
+ ]
96
+ end
97
+
98
+ it "should fail when column names are not specified" do
99
+ err = assert_raises ArgumentError do
100
+ Topic.import values, validate: false
101
+ end
102
+
103
+ assert err.message.include? 'Extra keys: [:author_email_address]'
104
+ end
105
+
106
+ it "should succeed when column names are specified" do
107
+ assert_difference "Topic.count", +2 do
108
+ Topic.import columns, values, validate: false
109
+ end
110
+ end
111
+ end
112
+
113
+ context "with missing keys" do
114
+ let(:values) do
115
+ [
116
+ { title: "LDAP", author_name: "Jerry Carter" },
117
+ { title: "Rails Recipes" } # author_name is missing
118
+ ]
119
+ end
120
+
121
+ it "should fail when column names are not specified" do
122
+ err = assert_raises ArgumentError do
123
+ Topic.import values, validate: false
124
+ end
125
+
126
+ assert err.message.include? 'Missing keys: [:author_name]'
127
+ end
128
+
129
+ it "should fail on missing hash key from specified column names" do
130
+ err = assert_raises ArgumentError do
131
+ Topic.import %i(author_name), values, validate: false
132
+ end
133
+
134
+ assert err.message.include? 'Missing keys: [:author_name]'
135
+ end
136
+ end
89
137
  end
90
138
 
91
139
  unless ENV["SKIP_COMPOSITE_PK"]
@@ -121,12 +169,12 @@ describe "#import" do
121
169
  end
122
170
 
123
171
  context "with :validation option" do
124
- let(:columns) { %w(title author_name) }
125
- let(:valid_values) { [["LDAP", "Jerry Carter"], ["Rails Recipes", "Chad Fowler"]] }
126
- let(:valid_values_with_context) { [[1111, "Jerry Carter"], [2222, "Chad Fowler"]] }
127
- let(:invalid_values) { [["The RSpec Book", ""], ["Agile+UX", ""]] }
128
- let(:valid_models) { valid_values.map { |title, author_name| Topic.new(title: title, author_name: author_name) } }
129
- let(:invalid_models) { invalid_values.map { |title, author_name| Topic.new(title: title, author_name: author_name) } }
172
+ let(:columns) { %w(title author_name content) }
173
+ let(:valid_values) { [["LDAP", "Jerry Carter", "Putting Directories to Work."], ["Rails Recipes", "Chad Fowler", "A trusted collection of solutions."]] }
174
+ let(:valid_values_with_context) { [[1111, "Jerry Carter", "1111"], [2222, "Chad Fowler", "2222"]] }
175
+ let(:invalid_values) { [["The RSpec Book", "David Chelimsky", "..."], ["Agile+UX", "", "All about Agile in UX."]] }
176
+ let(:valid_models) { valid_values.map { |title, author_name, content| Topic.new(title: title, author_name: author_name, content: content) } }
177
+ let(:invalid_models) { invalid_values.map { |title, author_name, content| Topic.new(title: title, author_name: author_name, content: content) } }
130
178
 
131
179
  context "with validation checks turned off" do
132
180
  it "should import valid data" do
@@ -162,9 +210,9 @@ describe "#import" do
162
210
  end
163
211
 
164
212
  it "should ignore uniqueness validators" do
165
- Topic.import columns, valid_values, validate: true
213
+ Topic.import columns, valid_values
166
214
  assert_difference "Topic.count", +2 do
167
- Topic.import columns, valid_values, validate: true
215
+ Topic.import columns, valid_values
168
216
  end
169
217
  end
170
218
 
@@ -200,7 +248,7 @@ describe "#import" do
200
248
  end
201
249
 
202
250
  it "should set ids in valid models if adapter supports setting primary key of imported objects" do
203
- if ActiveRecord::Base.support_setting_primary_key_of_imported_objects?
251
+ if ActiveRecord::Base.supports_setting_primary_key_of_imported_objects?
204
252
  Topic.import (invalid_models + valid_models), validate: true
205
253
  assert_nil invalid_models[0].id
206
254
  assert_nil invalid_models[1].id
@@ -210,7 +258,7 @@ describe "#import" do
210
258
  end
211
259
 
212
260
  it "should set ActiveRecord timestamps in valid models if adapter supports setting primary key of imported objects" do
213
- if ActiveRecord::Base.support_setting_primary_key_of_imported_objects?
261
+ if ActiveRecord::Base.supports_setting_primary_key_of_imported_objects?
214
262
  Timecop.freeze(Time.at(0)) do
215
263
  Topic.import (invalid_models + valid_models), validate: true
216
264
  end
@@ -246,6 +294,36 @@ describe "#import" do
246
294
  end
247
295
  end
248
296
  end
297
+
298
+ context "with uniqueness validators included" do
299
+ it "should not import duplicate records" do
300
+ Topic.import columns, valid_values
301
+ assert_no_difference "Topic.count" do
302
+ Topic.import columns, valid_values, validate_uniqueness: true
303
+ end
304
+ end
305
+ end
306
+
307
+ context "when validatoring presence of belongs_to association" do
308
+ it "should not import records without foreign key" do
309
+ assert_no_difference "UserToken.count" do
310
+ UserToken.import [:token], [['12345abcdef67890']]
311
+ end
312
+ end
313
+
314
+ it "should import records with foreign key" do
315
+ assert_difference "UserToken.count", +1 do
316
+ UserToken.import [:user_name, :token], [%w("Bob", "12345abcdef67890")]
317
+ end
318
+ end
319
+
320
+ it "should not mutate the defined validations" do
321
+ UserToken.import [:user_name, :token], [%w("Bob", "12345abcdef67890")]
322
+ ut = UserToken.new
323
+ ut.valid?
324
+ assert_includes ut.errors.messages, :user
325
+ end
326
+ end
249
327
  end
250
328
 
251
329
  context "without :validation option" do
@@ -320,7 +398,7 @@ describe "#import" do
320
398
 
321
399
  it "doesn't reload any data (doesn't work)" do
322
400
  Topic.import new_topics, synchronize: new_topics
323
- if Topic.support_setting_primary_key_of_imported_objects?
401
+ if Topic.supports_setting_primary_key_of_imported_objects?
324
402
  assert new_topics.all?(&:persisted?), "Records should have been reloaded"
325
403
  else
326
404
  assert new_topics.all?(&:new_record?), "No record should have been reloaded"
@@ -442,11 +520,11 @@ describe "#import" do
442
520
 
443
521
  context "when the timestamps columns are present" do
444
522
  setup do
445
- @existing_book = Book.create(title: "Fell", author_name: "Curry", publisher: "Bayer", created_at: 2.years.ago.utc, created_on: 2.years.ago.utc)
523
+ @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)
446
524
  ActiveRecord::Base.default_timezone = :utc
447
525
  Timecop.freeze(time) do
448
526
  assert_difference "Book.count", +2 do
449
- 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]]
527
+ 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]]
450
528
  end
451
529
  end
452
530
  @new_book, @existing_book = Book.last 2
@@ -475,6 +553,23 @@ describe "#import" do
475
553
  it "should set the updated_on column for new records" do
476
554
  assert_in_delta time.to_i, @new_book.updated_on.to_i, 1.second
477
555
  end
556
+
557
+ it "should not set the updated_at column for existing records" do
558
+ assert_equal 2.years.ago.utc.strftime("%Y:%d"), @existing_book.updated_at.strftime("%Y:%d")
559
+ end
560
+
561
+ it "should not set the updated_on column for existing records" do
562
+ assert_equal 2.years.ago.utc.strftime("%Y:%d"), @existing_book.updated_on.strftime("%Y:%d")
563
+ end
564
+
565
+ it "should not set the updated_at column on models if changed" do
566
+ timestamp = Time.now.utc
567
+ books = [
568
+ Book.new(author_name: "Foo", title: "Baz", created_at: timestamp, updated_at: timestamp)
569
+ ]
570
+ Book.import books
571
+ assert_equal timestamp.strftime("%Y:%d"), Book.last.updated_at.strftime("%Y:%d")
572
+ end
478
573
  end
479
574
 
480
575
  context "when a custom time zone is set" do
@@ -519,7 +614,7 @@ describe "#import" do
519
614
 
520
615
  context "importing through an association scope" do
521
616
  { has_many: :chapters, polymorphic: :discounts }.each do |association_type, association|
522
- book = FactoryGirl.create :book
617
+ book = FactoryBot.create :book
523
618
  scope = book.public_send association
524
619
  klass = { chapters: Chapter, discounts: Discount }[association]
525
620
  column = { chapters: :title, discounts: :amount }[association]
@@ -541,10 +636,35 @@ describe "#import" do
541
636
 
542
637
  assert_equal [val1, val2], scope.map(&column).sort
543
638
  end
639
+
640
+ it "works importing array of hashes" do
641
+ scope.import [{ column => val1 }, { column => val2 }]
642
+
643
+ assert_equal [val1, val2], scope.map(&column).sort
644
+ end
645
+ end
646
+
647
+ it "works with a non-standard association primary key" do
648
+ user = User.create(id: 1, name: 'Solomon')
649
+ user.user_tokens.import [:id, :token], [[5, '12345abcdef67890']]
650
+
651
+ token = UserToken.find(5)
652
+ assert_equal 'Solomon', token.user_name
544
653
  end
545
654
  end
546
655
  end
547
656
 
657
+ context "importing model with polymorphic belongs_to" do
658
+ it "works without error" do
659
+ book = FactoryBot.create :book
660
+ discount = Discount.new(discountable: book)
661
+
662
+ Discount.import([discount])
663
+
664
+ assert_equal 1, Discount.count
665
+ end
666
+ end
667
+
548
668
  context 'When importing models with Enum fields' do
549
669
  it 'should be able to import enum fields' do
550
670
  Book.delete_all if Book.count > 0
@@ -760,5 +880,19 @@ describe "#import" do
760
880
  end
761
881
  end
762
882
  end
883
+
884
+ context "with objects that respond to .to_sql as values" do
885
+ let(:columns) { %w(title author_name) }
886
+ let(:valid_values) { [["LDAP", Book.select("'Jerry Carter'").limit(1)], ["Rails Recipes", Book.select("'Chad Fowler'").limit(1)]] }
887
+
888
+ it "should import data" do
889
+ assert_difference "Topic.count", +2 do
890
+ Topic.import! columns, valid_values
891
+ topics = Topic.all
892
+ assert_equal "Jerry Carter", topics.first.author_name
893
+ assert_equal "Chad Fowler", topics.last.author_name
894
+ end
895
+ end
896
+ end
763
897
  end
764
898
  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,3 @@
1
+ class Account < ActiveRecord::Base
2
+ self.locking_column = :lock
3
+ end
@@ -0,0 +1,7 @@
1
+ module Bike
2
+ def self.table_name_prefix
3
+ 'bike_'
4
+ end
5
+ class Maker < ActiveRecord::Base
6
+ end
7
+ end
data/test/models/topic.rb CHANGED
@@ -2,6 +2,8 @@ class Topic < ActiveRecord::Base
2
2
  validates_presence_of :author_name
3
3
  validates :title, numericality: { only_integer: true }, on: :context_test
4
4
  validates :title, uniqueness: true
5
+ validates :content, uniqueness: true
6
+ validates :word_count, numericality: { greater_than: 0 }, if: :content?
5
7
 
6
8
  validate -> { errors.add(:title, :validate_failed) if title == 'validate_failed' }
7
9
  before_validation -> { errors.add(:title, :invalid) if title == 'invalid' }
@@ -10,4 +12,12 @@ class Topic < ActiveRecord::Base
10
12
  belongs_to :parent, class_name: "Topic"
11
13
 
12
14
  composed_of :description, mapping: [%w(title title), %w(author_name author_name)], allow_nil: true, class_name: "TopicDescription"
15
+
16
+ default_scope { where(approved: true) }
17
+
18
+ private
19
+
20
+ def word_count
21
+ @word_count ||= content.to_s.scan(/\w+/).count
22
+ end
13
23
  end
@@ -0,0 +1,3 @@
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
@@ -159,6 +159,26 @@ ActiveRecord::Schema.define do
159
159
  t.string :Features
160
160
  end
161
161
 
162
+ create_table :users, force: :cascade do |t|
163
+ t.string :name, null: false
164
+ t.integer :lock_version, null: false, default: 0
165
+ end
166
+
167
+ create_table :user_tokens, force: :cascade do |t|
168
+ t.string :user_name, null: false
169
+ t.string :token, null: false
170
+ end
171
+
172
+ create_table :accounts, force: :cascade do |t|
173
+ t.string :name, null: false
174
+ t.integer :lock, null: false, default: 0
175
+ end
176
+
177
+ create_table :bike_makers, force: :cascade do |t|
178
+ t.string :name, null: false
179
+ t.integer :lock_version, null: false, default: 0
180
+ end
181
+
162
182
  add_index :cars, :Name, unique: true
163
183
 
164
184
  unless ENV["SKIP_COMPOSITE_PK"]
@@ -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
@@ -36,6 +36,7 @@ ActiveRecord::Schema.define do
36
36
  t.column :alarm_type, :integer, null: false
37
37
  t.column :status, :integer, null: false
38
38
  t.column :metadata, :text
39
+ t.column :secret_key, :binary
39
40
  t.datetime :created_at
40
41
  t.datetime :updated_at
41
42
  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,12 +9,13 @@ 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
16
16
  sequence(:title) { |n| "Title #{n}" }
17
17
  sequence(:author_name) { |n| "Author #{n}" }
18
+ sequence(:content) { |n| "Content #{n}" }
18
19
  end
19
20
 
20
21
  factory :widget do
@@ -26,7 +27,7 @@ FactoryGirl.define do
26
27
 
27
28
  trait :with_rule do
28
29
  after(:build) do |question|
29
- question.build_rule(FactoryGirl.attributes_for(:rule))
30
+ question.build_rule(FactoryBot.attributes_for(:rule))
30
31
  end
31
32
  end
32
33
  end
@@ -39,21 +40,21 @@ FactoryGirl.define do
39
40
  factory :topic_with_book, parent: :topic do
40
41
  after(:build) do |topic|
41
42
  2.times do
42
- 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')
43
44
  3.times do
44
- book.chapters.build(title: FactoryGirl.generate(:chapter_title))
45
+ book.chapters.build(title: FactoryBot.generate(:chapter_title))
45
46
  end
46
47
 
47
48
  4.times do
48
- book.end_notes.build(note: FactoryGirl.generate(:end_note))
49
+ book.end_notes.build(note: FactoryBot.generate(:end_note))
49
50
  end
50
51
  end
51
52
  end
52
53
  end
53
54
 
54
55
  factory :book do
55
- title 'Tortilla Flat'
56
- author_name 'John Steinbeck'
56
+ title { 'Tortilla Flat' }
57
+ author_name { 'John Steinbeck' }
57
58
  end
58
59
 
59
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
@@ -64,8 +64,8 @@ def should_support_mysql_import_functionality
64
64
  let(:columns) { %w(id author_name title) }
65
65
 
66
66
  setup do
67
- topics << Topic.create!(title: "LDAP", author_name: "Big Bird")
68
- topics << Topic.create!(title: "Rails Recipes", author_name: "Elmo")
67
+ topics << Topic.create!(title: "LDAP", author_name: "Big Bird", content: "Putting Directories to Work.")
68
+ topics << Topic.create!(title: "Rails Recipes", author_name: "Elmo", content: "A trusted collection of solutions.")
69
69
  end
70
70
 
71
71
  it "synchronizes passed in ActiveRecord model instances with the data just imported" do
@@ -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