activerecord-import 0.20.2 → 0.21.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 +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +18 -0
- data/Gemfile +3 -3
- data/gemfiles/5.1.gemfile +1 -0
- data/lib/activerecord-import/import.rb +53 -3
- data/lib/activerecord-import/version.rb +1 -1
- data/test/import_test.rb +73 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d4441271287712d8e44b9cac793f2b8b8d315988
|
4
|
+
data.tar.gz: ec27555ffefb8a071bcf3c54b354a8b56b6e68c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbafbd6476a5f7c3681b26e85e3f4960fb69b6065697a173426392f91f1a89c188dd83b1b16c1639645ba33b8a1fbba97a91dea7e20186692c8ca3e33b9eaf41
|
7
|
+
data.tar.gz: 54f3499be94b3c1b44a99128c39bb9f964e5bcb8da8549dbd66fe5d568a14f195d8b60f2c17a8dab9b5745ba7efb9db58950b433377aee510f4586e1a3cf2074
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
## Changes in 0.21.0
|
2
|
+
|
3
|
+
### New Features
|
4
|
+
|
5
|
+
* Allow SQL subqueries (objects that respond to .to_sql) to be passed as values. Thanks
|
6
|
+
to @jalada, @jkowens via \#471
|
7
|
+
* Raise an ArgumentError when importing an array of hashes if any of the
|
8
|
+
hash objects have different keys. Thanks to @mbell697 via \#465.
|
9
|
+
|
10
|
+
### Fixes
|
11
|
+
|
12
|
+
* Fix issue loading incorrect foreign key value when syncing belongs_to
|
13
|
+
associations with custom foreign key columns. Thanks to @marcgreenstock, @jkowens via \#470.
|
14
|
+
* Fix issue importing models with polymorphic belongs_to associations.
|
15
|
+
Thanks to @zorab47, @jkowens via \#476.
|
16
|
+
* Fix issue importing STI models with ActiveRecord 4.0. Thanks to
|
17
|
+
@kazuki-st, @jkowens via \#478.
|
18
|
+
|
1
19
|
## Changes in 0.20.2
|
2
20
|
|
3
21
|
### Fixes
|
data/Gemfile
CHANGED
@@ -18,9 +18,9 @@ end
|
|
18
18
|
platforms :jruby do
|
19
19
|
gem "jdbc-mysql"
|
20
20
|
gem "jdbc-postgres"
|
21
|
-
gem "activerecord-jdbcsqlite3-adapter"
|
22
|
-
gem "activerecord-jdbcmysql-adapter"
|
23
|
-
gem "activerecord-jdbcpostgresql-adapter"
|
21
|
+
gem "activerecord-jdbcsqlite3-adapter", "~> 1.3"
|
22
|
+
gem "activerecord-jdbcmysql-adapter", "~> 1.3"
|
23
|
+
gem "activerecord-jdbcpostgresql-adapter", "~> 1.3"
|
24
24
|
end
|
25
25
|
|
26
26
|
# Support libs
|
data/gemfiles/5.1.gemfile
CHANGED
@@ -247,6 +247,9 @@ class ActiveRecord::Base
|
|
247
247
|
# BlogPost.import posts
|
248
248
|
#
|
249
249
|
# # Example using array_of_hash_objects
|
250
|
+
# # NOTE: column_names will be determined by using the keys of the first hash in the array. If later hashes in the
|
251
|
+
# # array have different keys an exception will be raised. If you have hashes to import with different sets of keys
|
252
|
+
# # we recommend grouping these into batches before importing.
|
250
253
|
# values = [ {author_name: 'zdennis', title: 'test post'} ], [ {author_name: 'jdoe', title: 'another test post'} ] ]
|
251
254
|
# BlogPost.import values
|
252
255
|
#
|
@@ -470,12 +473,18 @@ class ActiveRecord::Base
|
|
470
473
|
if args.length == 2
|
471
474
|
array_of_hashes = args.last
|
472
475
|
column_names = args.first.dup
|
476
|
+
allow_extra_hash_keys = true
|
473
477
|
else
|
474
478
|
array_of_hashes = args.first
|
475
479
|
column_names = array_of_hashes.first.keys
|
480
|
+
allow_extra_hash_keys = false
|
476
481
|
end
|
477
482
|
|
478
483
|
array_of_attributes = array_of_hashes.map do |h|
|
484
|
+
error_message = validate_hash_import(h, column_names, allow_extra_hash_keys)
|
485
|
+
|
486
|
+
raise ArgumentError, error_message if error_message
|
487
|
+
|
479
488
|
column_names.map do |key|
|
480
489
|
h[key]
|
481
490
|
end
|
@@ -613,7 +622,7 @@ class ActiveRecord::Base
|
|
613
622
|
next if column_names.include?(name_as_sym)
|
614
623
|
|
615
624
|
is_sti = (name_as_sym == inheritance_column.to_sym && self < base_class)
|
616
|
-
value = value.first if is_sti
|
625
|
+
value = Array(value).first if is_sti
|
617
626
|
|
618
627
|
column_names << name_as_sym
|
619
628
|
array_of_attributes.each { |attrs| attrs << value }
|
@@ -711,10 +720,12 @@ class ActiveRecord::Base
|
|
711
720
|
def load_association_ids(model)
|
712
721
|
association_reflections = model.class.reflect_on_all_associations(:belongs_to)
|
713
722
|
association_reflections.each do |association_reflection|
|
723
|
+
next if association_reflection.options[:polymorphic]
|
714
724
|
association = model.association(association_reflection.name)
|
715
725
|
association = association.target
|
716
|
-
if association
|
717
|
-
|
726
|
+
if association
|
727
|
+
association_primary_key = association_reflection.association_primary_key
|
728
|
+
model.public_send("#{association_reflection.foreign_key}=", association.send(association_primary_key))
|
718
729
|
end
|
719
730
|
end
|
720
731
|
end
|
@@ -782,6 +793,8 @@ class ActiveRecord::Base
|
|
782
793
|
# be sure to query sequence_name *last*, only if cheaper tests fail, because it's costly
|
783
794
|
if val.nil? && column.name == primary_key && !sequence_name.blank?
|
784
795
|
connection_memo.next_value_for_sequence(sequence_name)
|
796
|
+
elsif val.respond_to?(:to_sql)
|
797
|
+
"(#{val.to_sql})"
|
785
798
|
elsif column
|
786
799
|
if respond_to?(:type_caster) # Rails 5.0 and higher
|
787
800
|
type = type_for_attribute(column.name)
|
@@ -846,5 +859,42 @@ class ActiveRecord::Base
|
|
846
859
|
def validations_array_for_column_names_and_attributes( column_names, array_of_attributes ) # :nodoc:
|
847
860
|
array_of_attributes.map { |values| Hash[column_names.zip(values)] }
|
848
861
|
end
|
862
|
+
|
863
|
+
# Checks that the imported hash has the required_keys, optionally also checks that the hash has
|
864
|
+
# no keys beyond those required when `allow_extra_keys` is false.
|
865
|
+
# returns `nil` if validation passes, or an error message if it fails
|
866
|
+
def validate_hash_import(hash, required_keys, allow_extra_keys) # :nodoc:
|
867
|
+
extra_keys = allow_extra_keys ? [] : hash.keys - required_keys
|
868
|
+
missing_keys = required_keys - hash.keys
|
869
|
+
|
870
|
+
return nil if extra_keys.empty? && missing_keys.empty?
|
871
|
+
|
872
|
+
if allow_extra_keys
|
873
|
+
<<-EOS
|
874
|
+
Hash key mis-match.
|
875
|
+
|
876
|
+
When importing an array of hashes with provided columns_names, each hash must contain keys for all column_names.
|
877
|
+
|
878
|
+
Required keys: #{column_names}
|
879
|
+
Missing keys: #{missing_keys}
|
880
|
+
|
881
|
+
Hash: #{hash}
|
882
|
+
EOS
|
883
|
+
else
|
884
|
+
<<-EOS
|
885
|
+
Hash key mis-match.
|
886
|
+
|
887
|
+
When importing an array of hashes, all hashes must have the same keys.
|
888
|
+
If you have records that are missing some values, we recommend you either set default values
|
889
|
+
for the missing keys or group these records into batches by key set before importing.
|
890
|
+
|
891
|
+
Required keys: #{column_names}
|
892
|
+
Extra keys: #{extra_keys}
|
893
|
+
Missing keys: #{missing_keys}
|
894
|
+
|
895
|
+
Hash: #{hash}
|
896
|
+
EOS
|
897
|
+
end
|
898
|
+
end
|
849
899
|
end
|
850
900
|
end
|
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"]
|
@@ -545,6 +593,17 @@ describe "#import" do
|
|
545
593
|
end
|
546
594
|
end
|
547
595
|
|
596
|
+
context "importing model with polymorphic belongs_to" do
|
597
|
+
it "works without error" do
|
598
|
+
book = FactoryGirl.create :book
|
599
|
+
discount = Discount.new(discountable: book)
|
600
|
+
|
601
|
+
Discount.import([discount])
|
602
|
+
|
603
|
+
assert_equal 1, Discount.count
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
548
607
|
context 'When importing models with Enum fields' do
|
549
608
|
it 'should be able to import enum fields' do
|
550
609
|
Book.delete_all if Book.count > 0
|
@@ -760,5 +819,19 @@ describe "#import" do
|
|
760
819
|
end
|
761
820
|
end
|
762
821
|
end
|
822
|
+
|
823
|
+
context "with objects that respond to .to_sql as values" do
|
824
|
+
let(:columns) { %w(title author_name) }
|
825
|
+
let(:valid_values) { [["LDAP", Book.select("'Jerry Carter'").limit(1)], ["Rails Recipes", Book.select("'Chad Fowler'").limit(1)]] }
|
826
|
+
|
827
|
+
it "should import data" do
|
828
|
+
assert_difference "Topic.count", +2 do
|
829
|
+
Topic.import! columns, valid_values
|
830
|
+
topics = Topic.all
|
831
|
+
assert_equal "Jerry Carter", topics.first.author_name
|
832
|
+
assert_equal "Chad Fowler", topics.last.author_name
|
833
|
+
end
|
834
|
+
end
|
835
|
+
end
|
763
836
|
end
|
764
837
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-import
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Dennis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -176,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
176
176
|
version: '0'
|
177
177
|
requirements: []
|
178
178
|
rubyforge_project:
|
179
|
-
rubygems_version: 2.6.
|
179
|
+
rubygems_version: 2.6.13
|
180
180
|
signing_key:
|
181
181
|
specification_version: 4
|
182
182
|
summary: Bulk insert extension for ActiveRecord
|