activerecord-import 0.19.0 → 0.28.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +22 -12
- data/CHANGELOG.md +151 -0
- data/Gemfile +13 -10
- data/README.markdown +548 -5
- data/Rakefile +2 -1
- data/benchmarks/lib/cli_parser.rb +2 -1
- data/gemfiles/5.1.gemfile +1 -0
- data/gemfiles/5.2.gemfile +2 -0
- data/lib/activerecord-import/adapters/abstract_adapter.rb +2 -2
- data/lib/activerecord-import/adapters/mysql_adapter.rb +15 -6
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +59 -15
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +126 -3
- data/lib/activerecord-import/base.rb +4 -6
- data/lib/activerecord-import/import.rb +381 -126
- data/lib/activerecord-import/synchronize.rb +1 -1
- data/lib/activerecord-import/value_sets_parser.rb +14 -0
- data/lib/activerecord-import/version.rb +1 -1
- data/lib/activerecord-import.rb +2 -15
- data/test/adapters/makara_postgis.rb +1 -0
- data/test/import_test.rb +148 -14
- data/test/makara_postgis/import_test.rb +8 -0
- data/test/models/account.rb +3 -0
- data/test/models/bike_maker.rb +7 -0
- data/test/models/topic.rb +10 -0
- data/test/models/user.rb +3 -0
- data/test/models/user_token.rb +4 -0
- data/test/schema/generic_schema.rb +20 -0
- data/test/schema/mysql2_schema.rb +19 -0
- data/test/schema/postgresql_schema.rb +1 -0
- data/test/schema/sqlite3_schema.rb +13 -0
- data/test/support/factories.rb +9 -8
- data/test/support/generate.rb +6 -6
- data/test/support/mysql/import_examples.rb +14 -2
- data/test/support/postgresql/import_examples.rb +136 -0
- data/test/support/shared_examples/on_duplicate_key_update.rb +252 -1
- data/test/support/shared_examples/recursive_import.rb +41 -11
- data/test/support/sqlite3/import_examples.rb +187 -10
- data/test/synchronize_test.rb +8 -0
- data/test/test_helper.rb +9 -1
- data/test/value_sets_bytes_parser_test.rb +13 -2
- metadata +19 -4
- 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
|
data/lib/activerecord-import.rb
CHANGED
@@ -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
|
-
|
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
|
213
|
+
Topic.import columns, valid_values
|
166
214
|
assert_difference "Topic.count", +2 do
|
167
|
-
Topic.import columns, valid_values
|
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.
|
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.
|
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.
|
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 =
|
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
|
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
|
data/test/models/user.rb
ADDED
@@ -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
|
@@ -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,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(
|
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:
|
43
|
+
book = topic.books.build(title: FactoryBot.generate(:book_title), author_name: 'Stephen King')
|
43
44
|
3.times do
|
44
|
-
book.chapters.build(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:
|
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
|
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
|
@@ -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
|