activerecord-import 0.20.2 → 0.21.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|