activerecord-import 0.19.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +22 -12
- data/CHANGELOG.md +166 -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 +16 -10
- 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 +384 -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 +142 -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 +20 -5
- 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
|