activerecord-import 0.18.1 → 0.18.2
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 +2 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +1 -1
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +1 -1
- data/lib/activerecord-import/import.rb +47 -36
- data/lib/activerecord-import/version.rb +1 -1
- data/test/import_test.rb +15 -0
- data/test/models/topic.rb +1 -0
- data/test/support/shared_examples/on_duplicate_key_ignore.rb +6 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ebf1fdae1a4d300498ed6ba18ea8d4039697734
|
4
|
+
data.tar.gz: 41e6dfff68a59c0fd9184691cbe6731cc420df8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba3161f35e5521a4febe1a66e729f9a9c549620f54119992d87a834148dc3a42f9e28f3f4c4ca9fb722a0c73639ca678db6d9363325fe6e73a5fb61b58422c59
|
7
|
+
data.tar.gz: 4248f96c0adbd65300e1ba161ea91fcf707ac151523121ac9bc541d24cec8f32229bde28ac1783ea6ec69c1f3043f3ac5b5a06c094d2fe9f2c04f952128a0cf6
|
data/.travis.yml
CHANGED
@@ -27,9 +27,6 @@ matrix:
|
|
27
27
|
- bundle exec rake test:jdbcmysql
|
28
28
|
- bundle exec rake test:jdbcpostgresql
|
29
29
|
|
30
|
-
allow_failures:
|
31
|
-
- env: AR_VERSION=5.1
|
32
|
-
|
33
30
|
fast_finish: true
|
34
31
|
|
35
32
|
before_script:
|
@@ -47,6 +44,7 @@ addons:
|
|
47
44
|
- travis-ci/sqlite3
|
48
45
|
packages:
|
49
46
|
- sqlite3
|
47
|
+
- postgresql-9.5-postgis-2.3
|
50
48
|
|
51
49
|
script:
|
52
50
|
- bundle exec rake test:mysql2
|
@@ -60,4 +58,4 @@ script:
|
|
60
58
|
- bundle exec rake test:sqlite3
|
61
59
|
- bundle exec rubocop
|
62
60
|
|
63
|
-
|
61
|
+
dist: trusty
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## Changes in 0.18.2
|
2
|
+
|
3
|
+
### Fixes
|
4
|
+
|
5
|
+
* Enable custom validate callbacks when validating import. Thanks to @afn via \#410.
|
6
|
+
* Prevent wrong IDs being set on models when using :on_duplicate_key_ignore.
|
7
|
+
Thanks to @afn, @jkowens via \#412.
|
8
|
+
|
1
9
|
## Changes in 0.18.1
|
2
10
|
|
3
11
|
### Fixes
|
data/Gemfile
CHANGED
@@ -50,7 +50,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
50
50
|
|
51
51
|
sql += super(table_name, options)
|
52
52
|
|
53
|
-
unless options[:
|
53
|
+
unless options[:primary_key].blank? || options[:no_returning]
|
54
54
|
primary_key = Array(options[:primary_key])
|
55
55
|
sql << " RETURNING \"#{primary_key.join('", "')}\""
|
56
56
|
end
|
@@ -24,9 +24,8 @@ module ActiveRecord::Import #:nodoc:
|
|
24
24
|
end
|
25
25
|
|
26
26
|
class Validator
|
27
|
-
def initialize(
|
28
|
-
@
|
29
|
-
@options = options
|
27
|
+
def initialize(options = {})
|
28
|
+
@options = options
|
30
29
|
end
|
31
30
|
|
32
31
|
def valid_model?(model)
|
@@ -34,38 +33,47 @@ module ActiveRecord::Import #:nodoc:
|
|
34
33
|
validation_context ||= (model.new_record? ? :create : :update)
|
35
34
|
|
36
35
|
current_context = model.send(:validation_context)
|
37
|
-
|
38
|
-
|
36
|
+
begin
|
37
|
+
model.send(:validation_context=, validation_context)
|
38
|
+
model.errors.clear
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
if
|
43
|
-
v.validate(model) if validate?(v, model)
|
44
|
-
end
|
40
|
+
validate_callbacks = model._validate_callbacks.dup
|
41
|
+
validate_callbacks.each do |callback|
|
42
|
+
validate_callbacks.delete(callback) if callback.raw_filter.is_a? ActiveRecord::Validations::UniquenessValidator
|
45
43
|
end
|
46
|
-
end
|
47
|
-
|
48
|
-
if model.respond_to?(:run_validation_callbacks)
|
49
|
-
model.send(:_run_validation_callbacks, &validation_proc)
|
50
|
-
else
|
51
|
-
model.send(:run_callbacks, :validation, &validation_proc)
|
52
|
-
end
|
53
|
-
|
54
|
-
model.send(:validation_context=, current_context)
|
55
|
-
model.errors.empty?
|
56
|
-
end
|
57
44
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
45
|
+
model.run_callbacks(:validation) do
|
46
|
+
if defined?(ActiveSupport::Callbacks::Filters::Environment) # ActiveRecord >= 4.1
|
47
|
+
runner = validate_callbacks.compile
|
48
|
+
env = ActiveSupport::Callbacks::Filters::Environment.new(model, false, nil)
|
49
|
+
if runner.respond_to?(:call) # ActiveRecord < 5.1
|
50
|
+
runner.call(env)
|
51
|
+
else # ActiveRecord 5.1
|
52
|
+
# Note that this is a gross simplification of ActiveSupport::Callbacks#run_callbacks.
|
53
|
+
# It's technically possible for there to exist an "around" callback in the
|
54
|
+
# :validate chain, but this would be an aberration, since Rails doesn't define
|
55
|
+
# "around_validate". Still, rather than silently ignoring such callbacks, we
|
56
|
+
# explicitly raise a RuntimeError, since activerecord-import was asked to perform
|
57
|
+
# validations and it's unable to do so.
|
58
|
+
#
|
59
|
+
# The alternative here would be to copy-and-paste the bulk of the
|
60
|
+
# ActiveSupport::Callbacks#run_callbacks method, which is undesirable if there's
|
61
|
+
# no real-world use case for it.
|
62
|
+
raise "The :validate callback chain contains an 'around' callback, which is unsupported" unless runner.final?
|
63
|
+
runner.invoke_before(env)
|
64
|
+
runner.invoke_after(env)
|
65
|
+
end
|
66
|
+
elsif validate_callbacks.method(:compile).arity == 0 # ActiveRecord = 4.0
|
67
|
+
model.instance_eval validate_callbacks.compile
|
68
|
+
else # ActiveRecord 3.x
|
69
|
+
model.instance_eval validate_callbacks.compile(nil, model)
|
70
|
+
end
|
64
71
|
end
|
65
|
-
end
|
66
72
|
|
67
|
-
|
68
|
-
|
73
|
+
model.errors.empty?
|
74
|
+
ensure
|
75
|
+
model.send(:validation_context=, current_context)
|
76
|
+
end
|
69
77
|
end
|
70
78
|
end
|
71
79
|
end
|
@@ -212,7 +220,9 @@ class ActiveRecord::Base
|
|
212
220
|
# records that contain duplicate keys. For Postgres 9.5+ it adds
|
213
221
|
# ON CONFLICT DO NOTHING, for MySQL it uses INSERT IGNORE, and for
|
214
222
|
# SQLite it uses INSERT OR IGNORE. Cannot be enabled on a
|
215
|
-
# recursive import.
|
223
|
+
# recursive import. For database adapters that normally support
|
224
|
+
# setting primary keys on imported objects, this option prevents
|
225
|
+
# that from occurring.
|
216
226
|
# * +on_duplicate_key_update+ - an Array or Hash, tells import to
|
217
227
|
# use MySQL's ON DUPLICATE KEY UPDATE or Postgres 9.5+ ON CONFLICT
|
218
228
|
# DO UPDATE ability. See On Duplicate Key Update below.
|
@@ -511,7 +521,9 @@ class ActiveRecord::Base
|
|
511
521
|
|
512
522
|
# if we have ids, then set the id on the models and mark the models as clean.
|
513
523
|
if models && support_setting_primary_key_of_imported_objects?
|
514
|
-
|
524
|
+
if options[:recursive] || !(options[:ignore] || options[:on_duplicate_key_ignore])
|
525
|
+
set_attributes_and_mark_clean(models, return_obj, timestamps)
|
526
|
+
end
|
515
527
|
|
516
528
|
# if there are auto-save associations on the models we imported that are new, import them as well
|
517
529
|
import_associations(models, options.dup) if options[:recursive]
|
@@ -530,8 +542,7 @@ class ActiveRecord::Base
|
|
530
542
|
def import_with_validations( column_names, array_of_attributes, options = {} )
|
531
543
|
failed_instances = []
|
532
544
|
|
533
|
-
|
534
|
-
validator = ActiveRecord::Import::Validator.new(validators, options)
|
545
|
+
validator = ActiveRecord::Import::Validator.new(options)
|
535
546
|
|
536
547
|
if block_given?
|
537
548
|
yield validator, failed_instances
|
@@ -700,8 +711,8 @@ class ActiveRecord::Base
|
|
700
711
|
# Returns SQL the VALUES for an INSERT statement given the passed in +columns+
|
701
712
|
# and +array_of_attributes+.
|
702
713
|
def values_sql_for_columns_and_attributes(columns, array_of_attributes) # :nodoc:
|
703
|
-
# connection
|
704
|
-
# Reuse the same
|
714
|
+
# connection gets called a *lot* in this high intensity loop.
|
715
|
+
# Reuse the same one w/in the loop, otherwise it would keep being re-retreived (= lots of time for large imports)
|
705
716
|
connection_memo = connection
|
706
717
|
|
707
718
|
array_of_attributes.map do |arr|
|
data/test/import_test.rb
CHANGED
@@ -168,6 +168,15 @@ describe "#import" do
|
|
168
168
|
end
|
169
169
|
end
|
170
170
|
|
171
|
+
it "should not alter the callback chain of the model" do
|
172
|
+
attributes = columns.zip(valid_values.first).to_h
|
173
|
+
topic = Topic.new attributes
|
174
|
+
Topic.import [topic], validate: true
|
175
|
+
duplicate_topic = Topic.new attributes
|
176
|
+
Topic.import [duplicate_topic], validate: true
|
177
|
+
assert duplicate_topic.invalid?
|
178
|
+
end
|
179
|
+
|
171
180
|
it "should not import invalid data" do
|
172
181
|
assert_no_difference "Topic.count" do
|
173
182
|
Topic.import columns, invalid_values, validate: true
|
@@ -230,6 +239,12 @@ describe "#import" do
|
|
230
239
|
Topic.import columns, [["invalid", "Jerry Carter"]], validate: true
|
231
240
|
end
|
232
241
|
end
|
242
|
+
|
243
|
+
it "should call validation methods" do
|
244
|
+
assert_no_difference "Topic.count" do
|
245
|
+
Topic.import columns, [["validate_failed", "Jerry Carter"]], validate: true
|
246
|
+
end
|
247
|
+
end
|
233
248
|
end
|
234
249
|
end
|
235
250
|
|
data/test/models/topic.rb
CHANGED
@@ -3,6 +3,7 @@ class Topic < ActiveRecord::Base
|
|
3
3
|
validates :title, numericality: { only_integer: true }, on: :context_test
|
4
4
|
validates :title, uniqueness: true
|
5
5
|
|
6
|
+
validate -> { errors.add(:title, :validate_failed) if title == 'validate_failed' }
|
6
7
|
before_validation -> { errors.add(:title, :invalid) if title == 'invalid' }
|
7
8
|
|
8
9
|
has_many :books, inverse_of: :topic
|
@@ -8,7 +8,9 @@ def should_support_on_duplicate_key_ignore
|
|
8
8
|
it "should skip duplicates and continue import" do
|
9
9
|
topics << Topic.new(title: "Book 2", author_name: "Jane Doe")
|
10
10
|
assert_difference "Topic.count", +1 do
|
11
|
-
Topic.import topics, on_duplicate_key_ignore: true, validate: false
|
11
|
+
result = Topic.import topics, on_duplicate_key_ignore: true, validate: false
|
12
|
+
assert_not_equal topics.first.id, result.ids.first
|
13
|
+
assert_nil topics.last.id
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
@@ -31,7 +33,9 @@ def should_support_on_duplicate_key_ignore
|
|
31
33
|
it "should skip duplicates and continue import" do
|
32
34
|
topics << Topic.new(title: "Book 2", author_name: "Jane Doe")
|
33
35
|
assert_difference "Topic.count", +1 do
|
34
|
-
Topic.import topics, ignore: true, validate: false
|
36
|
+
result = Topic.import topics, ignore: true, validate: false
|
37
|
+
assert_not_equal topics.first.id, result.ids.first
|
38
|
+
assert_nil topics.last.id
|
35
39
|
end
|
36
40
|
end
|
37
41
|
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.18.
|
4
|
+
version: 0.18.2
|
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-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|