activerecord-import 1.0.0 → 1.0.5
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 +17 -14
- data/CHANGELOG.md +65 -0
- data/Gemfile +4 -1
- data/LICENSE +21 -56
- data/README.markdown +54 -59
- data/activerecord-import.gemspec +2 -2
- data/gemfiles/6.0.gemfile +1 -0
- data/gemfiles/6.1.gemfile +1 -0
- data/lib/activerecord-import/adapters/abstract_adapter.rb +8 -2
- data/lib/activerecord-import/adapters/mysql_adapter.rb +4 -5
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +11 -12
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +15 -20
- data/lib/activerecord-import/base.rb +8 -1
- data/lib/activerecord-import/import.rb +41 -36
- data/lib/activerecord-import/synchronize.rb +1 -1
- data/lib/activerecord-import/version.rb +1 -1
- data/test/import_test.rb +5 -0
- data/test/schema/postgresql_schema.rb +16 -0
- data/test/support/postgresql/import_examples.rb +44 -0
- data/test/support/shared_examples/on_duplicate_key_update.rb +10 -0
- data/test/support/shared_examples/recursive_import.rb +38 -0
- data/test/support/sqlite3/import_examples.rb +2 -15
- metadata +7 -6
data/activerecord-import.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |gem|
|
|
7
7
|
gem.summary = "Bulk insert extension for ActiveRecord"
|
8
8
|
gem.description = "A library for bulk inserting data using ActiveRecord."
|
9
9
|
gem.homepage = "http://github.com/zdennis/activerecord-import"
|
10
|
-
gem.license = "
|
10
|
+
gem.license = "MIT"
|
11
11
|
|
12
12
|
gem.files = `git ls-files`.split($\)
|
13
13
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.require_paths = ["lib"]
|
17
17
|
gem.version = ActiveRecord::Import::VERSION
|
18
18
|
|
19
|
-
gem.required_ruby_version = ">=
|
19
|
+
gem.required_ruby_version = ">= 2.0.0"
|
20
20
|
|
21
21
|
gem.add_runtime_dependency "activerecord", ">= 3.2"
|
22
22
|
gem.add_development_dependency "rake"
|
@@ -0,0 +1 @@
|
|
1
|
+
gem 'activerecord', '~> 6.0.0'
|
@@ -0,0 +1 @@
|
|
1
|
+
gem 'activerecord', '~> 6.1.0.alpha', github: "rails/rails"
|
@@ -46,7 +46,7 @@ module ActiveRecord::Import::AbstractAdapter
|
|
46
46
|
|
47
47
|
if supports_on_duplicate_key_update? && options[:on_duplicate_key_update]
|
48
48
|
post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update], options[:primary_key], options[:locking_column] )
|
49
|
-
elsif options[:on_duplicate_key_update]
|
49
|
+
elsif logger && options[:on_duplicate_key_update]
|
50
50
|
logger.warn "Ignoring on_duplicate_key_update because it is not supported by the database."
|
51
51
|
end
|
52
52
|
|
@@ -59,8 +59,14 @@ module ActiveRecord::Import::AbstractAdapter
|
|
59
59
|
post_sql_statements
|
60
60
|
end
|
61
61
|
|
62
|
+
def increment_locking_column!(table_name, results, locking_column)
|
63
|
+
if locking_column.present?
|
64
|
+
results << "\"#{locking_column}\"=#{table_name}.\"#{locking_column}\"+1"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
62
68
|
def supports_on_duplicate_key_update?
|
63
|
-
|
69
|
+
true
|
64
70
|
end
|
65
71
|
end
|
66
72
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module ActiveRecord::Import::MysqlAdapter
|
2
2
|
include ActiveRecord::Import::ImportSupport
|
3
|
-
include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
|
4
3
|
|
5
4
|
NO_MAX_PACKET = 0
|
6
5
|
QUERY_OVERHEAD = 8 # This was shown to be true for MySQL, but it's not clear where the overhead is from.
|
@@ -102,7 +101,7 @@ module ActiveRecord::Import::MysqlAdapter
|
|
102
101
|
qc = quote_column_name( column )
|
103
102
|
"#{table_name}.#{qc}=VALUES(#{qc})"
|
104
103
|
end
|
105
|
-
increment_locking_column!(
|
104
|
+
increment_locking_column!(table_name, results, locking_column)
|
106
105
|
results.join( ',' )
|
107
106
|
end
|
108
107
|
|
@@ -112,7 +111,7 @@ module ActiveRecord::Import::MysqlAdapter
|
|
112
111
|
qc2 = quote_column_name( column2 )
|
113
112
|
"#{table_name}.#{qc1}=VALUES( #{qc2} )"
|
114
113
|
end
|
115
|
-
increment_locking_column!(
|
114
|
+
increment_locking_column!(table_name, results, locking_column)
|
116
115
|
results.join( ',')
|
117
116
|
end
|
118
117
|
|
@@ -121,9 +120,9 @@ module ActiveRecord::Import::MysqlAdapter
|
|
121
120
|
exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('Duplicate entry')
|
122
121
|
end
|
123
122
|
|
124
|
-
def increment_locking_column!(
|
123
|
+
def increment_locking_column!(table_name, results, locking_column)
|
125
124
|
if locking_column.present?
|
126
|
-
results << "
|
125
|
+
results << "`#{locking_column}`=#{table_name}.`#{locking_column}`+1"
|
127
126
|
end
|
128
127
|
end
|
129
128
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module ActiveRecord::Import::PostgreSQLAdapter
|
2
2
|
include ActiveRecord::Import::ImportSupport
|
3
|
-
include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
|
4
3
|
|
5
4
|
MIN_VERSION_FOR_UPSERT = 90_500
|
6
5
|
|
@@ -19,7 +18,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
19
18
|
sql2insert = base_sql + values.join( ',' ) + post_sql
|
20
19
|
|
21
20
|
columns = returning_columns(options)
|
22
|
-
if columns.blank? || options[:no_returning]
|
21
|
+
if columns.blank? || (options[:no_returning] && !options[:recursive])
|
23
22
|
insert( sql2insert, *args )
|
24
23
|
else
|
25
24
|
returned_values = if columns.size > 1
|
@@ -73,14 +72,14 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
73
72
|
if (options[:ignore] || options[:on_duplicate_key_ignore]) && !options[:on_duplicate_key_update] && !options[:recursive]
|
74
73
|
sql << sql_for_on_duplicate_key_ignore( table_name, options[:on_duplicate_key_ignore] )
|
75
74
|
end
|
76
|
-
elsif options[:on_duplicate_key_ignore] && !options[:on_duplicate_key_update]
|
75
|
+
elsif logger && options[:on_duplicate_key_ignore] && !options[:on_duplicate_key_update]
|
77
76
|
logger.warn "Ignoring on_duplicate_key_ignore because it is not supported by the database."
|
78
77
|
end
|
79
78
|
|
80
79
|
sql += super(table_name, options)
|
81
80
|
|
82
81
|
columns = returning_columns(options)
|
83
|
-
unless columns.blank? || options[:no_returning]
|
82
|
+
unless columns.blank? || (options[:no_returning] && !options[:recursive])
|
84
83
|
sql << " RETURNING \"#{columns.join('", "')}\""
|
85
84
|
end
|
86
85
|
|
@@ -158,7 +157,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
158
157
|
qc = quote_column_name( column )
|
159
158
|
"#{qc}=EXCLUDED.#{qc}"
|
160
159
|
end
|
161
|
-
increment_locking_column!(results, locking_column)
|
160
|
+
increment_locking_column!(table_name, results, locking_column)
|
162
161
|
results.join( ',' )
|
163
162
|
end
|
164
163
|
|
@@ -168,7 +167,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
168
167
|
qc2 = quote_column_name( column2 )
|
169
168
|
"#{qc1}=EXCLUDED.#{qc2}"
|
170
169
|
end
|
171
|
-
increment_locking_column!(results, locking_column)
|
170
|
+
increment_locking_column!(table_name, results, locking_column)
|
172
171
|
results.join( ',' )
|
173
172
|
end
|
174
173
|
|
@@ -195,17 +194,17 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
195
194
|
exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('duplicate key')
|
196
195
|
end
|
197
196
|
|
198
|
-
def supports_on_duplicate_key_update?
|
199
|
-
|
197
|
+
def supports_on_duplicate_key_update?
|
198
|
+
database_version >= MIN_VERSION_FOR_UPSERT
|
200
199
|
end
|
201
200
|
|
202
201
|
def supports_setting_primary_key_of_imported_objects?
|
203
202
|
true
|
204
203
|
end
|
205
204
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
205
|
+
private
|
206
|
+
|
207
|
+
def database_version
|
208
|
+
defined?(postgresql_version) ? postgresql_version : super
|
210
209
|
end
|
211
210
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module ActiveRecord::Import::SQLite3Adapter
|
2
2
|
include ActiveRecord::Import::ImportSupport
|
3
|
-
include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
|
4
3
|
|
5
4
|
MIN_VERSION_FOR_IMPORT = "3.7.11".freeze
|
6
5
|
MIN_VERSION_FOR_UPSERT = "3.24.0".freeze
|
@@ -9,16 +8,12 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
9
8
|
# Override our conformance to ActiveRecord::Import::ImportSupport interface
|
10
9
|
# to ensure that we only support import in supported version of SQLite.
|
11
10
|
# Which INSERT statements with multiple value sets was introduced in 3.7.11.
|
12
|
-
def supports_import?
|
13
|
-
|
14
|
-
true
|
15
|
-
else
|
16
|
-
false
|
17
|
-
end
|
11
|
+
def supports_import?
|
12
|
+
database_version >= MIN_VERSION_FOR_IMPORT
|
18
13
|
end
|
19
14
|
|
20
|
-
def supports_on_duplicate_key_update?
|
21
|
-
|
15
|
+
def supports_on_duplicate_key_update?
|
16
|
+
database_version >= MIN_VERSION_FOR_UPSERT
|
22
17
|
end
|
23
18
|
|
24
19
|
# +sql+ can be a single string or an array. If it is an array all
|
@@ -96,7 +91,7 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
96
91
|
|
97
92
|
# Returns a generated ON CONFLICT DO UPDATE statement given the passed
|
98
93
|
# in +args+.
|
99
|
-
def sql_for_on_duplicate_key_update(
|
94
|
+
def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
|
100
95
|
arg, primary_key, locking_column = args
|
101
96
|
arg = { columns: arg } if arg.is_a?( Array ) || arg.is_a?( String )
|
102
97
|
return unless arg.is_a?( Hash )
|
@@ -117,9 +112,9 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
117
112
|
|
118
113
|
sql << "#{conflict_target}DO UPDATE SET "
|
119
114
|
if columns.is_a?( Array )
|
120
|
-
sql << sql_for_on_duplicate_key_update_as_array( locking_column, columns )
|
115
|
+
sql << sql_for_on_duplicate_key_update_as_array( table_name, locking_column, columns )
|
121
116
|
elsif columns.is_a?( Hash )
|
122
|
-
sql << sql_for_on_duplicate_key_update_as_hash( locking_column, columns )
|
117
|
+
sql << sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, columns )
|
123
118
|
elsif columns.is_a?( String )
|
124
119
|
sql << columns
|
125
120
|
else
|
@@ -131,22 +126,22 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
131
126
|
sql
|
132
127
|
end
|
133
128
|
|
134
|
-
def sql_for_on_duplicate_key_update_as_array( locking_column, arr ) # :nodoc:
|
129
|
+
def sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arr ) # :nodoc:
|
135
130
|
results = arr.map do |column|
|
136
131
|
qc = quote_column_name( column )
|
137
132
|
"#{qc}=EXCLUDED.#{qc}"
|
138
133
|
end
|
139
|
-
increment_locking_column!(results, locking_column)
|
134
|
+
increment_locking_column!(table_name, results, locking_column)
|
140
135
|
results.join( ',' )
|
141
136
|
end
|
142
137
|
|
143
|
-
def sql_for_on_duplicate_key_update_as_hash( locking_column, hsh ) # :nodoc:
|
138
|
+
def sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, hsh ) # :nodoc:
|
144
139
|
results = hsh.map do |column1, column2|
|
145
140
|
qc1 = quote_column_name( column1 )
|
146
141
|
qc2 = quote_column_name( column2 )
|
147
142
|
"#{qc1}=EXCLUDED.#{qc2}"
|
148
143
|
end
|
149
|
-
increment_locking_column!(results, locking_column)
|
144
|
+
increment_locking_column!(table_name, results, locking_column)
|
150
145
|
results.join( ',' )
|
151
146
|
end
|
152
147
|
|
@@ -170,9 +165,9 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
170
165
|
exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('duplicate key')
|
171
166
|
end
|
172
167
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
168
|
+
private
|
169
|
+
|
170
|
+
def database_version
|
171
|
+
defined?(sqlite_version) ? sqlite_version : super
|
177
172
|
end
|
178
173
|
end
|
@@ -13,6 +13,7 @@ module ActiveRecord::Import
|
|
13
13
|
when 'postgresql_makara' then 'postgresql'
|
14
14
|
when 'makara_postgis' then 'postgresql'
|
15
15
|
when 'postgis' then 'postgresql'
|
16
|
+
when 'cockroachdb' then 'postgresql'
|
16
17
|
else adapter
|
17
18
|
end
|
18
19
|
end
|
@@ -26,7 +27,13 @@ module ActiveRecord::Import
|
|
26
27
|
|
27
28
|
# Loads the import functionality for the passed in ActiveRecord connection
|
28
29
|
def self.load_from_connection_pool(connection_pool)
|
29
|
-
|
30
|
+
adapter =
|
31
|
+
if connection_pool.respond_to?(:db_config) # ActiveRecord >= 6.1
|
32
|
+
connection_pool.db_config.adapter
|
33
|
+
else
|
34
|
+
connection_pool.spec.config[:adapter]
|
35
|
+
end
|
36
|
+
require_adapter adapter
|
30
37
|
end
|
31
38
|
end
|
32
39
|
|
@@ -11,12 +11,6 @@ module ActiveRecord::Import #:nodoc:
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
module OnDuplicateKeyUpdateSupport #:nodoc:
|
15
|
-
def supports_on_duplicate_key_update? #:nodoc:
|
16
|
-
true
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
14
|
class MissingColumnError < StandardError
|
21
15
|
def initialize(name, index)
|
22
16
|
super "Missing column for value <#{name}> at index #{index}"
|
@@ -26,6 +20,7 @@ module ActiveRecord::Import #:nodoc:
|
|
26
20
|
class Validator
|
27
21
|
def initialize(klass, options = {})
|
28
22
|
@options = options
|
23
|
+
@validator_class = klass
|
29
24
|
init_validations(klass)
|
30
25
|
end
|
31
26
|
|
@@ -70,6 +65,8 @@ module ActiveRecord::Import #:nodoc:
|
|
70
65
|
end
|
71
66
|
|
72
67
|
def valid_model?(model)
|
68
|
+
init_validations(model.class) unless model.class == @validator_class
|
69
|
+
|
73
70
|
validation_context = @options[:validate_with_context]
|
74
71
|
validation_context ||= (model.new_record? ? :create : :update)
|
75
72
|
current_context = model.send(:validation_context)
|
@@ -242,16 +239,17 @@ class ActiveRecord::Associations::CollectionAssociation
|
|
242
239
|
alias import bulk_import unless respond_to? :import
|
243
240
|
end
|
244
241
|
|
242
|
+
module ActiveRecord::Import::Connection
|
243
|
+
def establish_connection(args = nil)
|
244
|
+
conn = super(args)
|
245
|
+
ActiveRecord::Import.load_from_connection_pool connection_pool
|
246
|
+
conn
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
245
250
|
class ActiveRecord::Base
|
246
251
|
class << self
|
247
|
-
|
248
|
-
conn = establish_connection_without_activerecord_import(*args)
|
249
|
-
ActiveRecord::Import.load_from_connection_pool connection_pool
|
250
|
-
conn
|
251
|
-
end
|
252
|
-
|
253
|
-
alias establish_connection_without_activerecord_import establish_connection
|
254
|
-
alias establish_connection establish_connection_with_activerecord_import
|
252
|
+
prepend ActiveRecord::Import::Connection
|
255
253
|
|
256
254
|
# Returns true if the current database connection adapter
|
257
255
|
# supports import functionality, otherwise returns false.
|
@@ -528,7 +526,7 @@ class ActiveRecord::Base
|
|
528
526
|
import_helper(*args)
|
529
527
|
end
|
530
528
|
end
|
531
|
-
alias import bulk_import unless respond_to? :import
|
529
|
+
alias import bulk_import unless ActiveRecord::Base.respond_to? :import
|
532
530
|
|
533
531
|
# Imports a collection of values if all values are valid. Import fails at the
|
534
532
|
# first encountered validation error and raises ActiveRecord::RecordInvalid
|
@@ -540,7 +538,7 @@ class ActiveRecord::Base
|
|
540
538
|
|
541
539
|
bulk_import(*args, options)
|
542
540
|
end
|
543
|
-
alias import! bulk_import! unless respond_to? :import!
|
541
|
+
alias import! bulk_import! unless ActiveRecord::Base.respond_to? :import!
|
544
542
|
|
545
543
|
def import_helper( *args )
|
546
544
|
options = { validate: true, timestamps: true }
|
@@ -574,15 +572,6 @@ class ActiveRecord::Base
|
|
574
572
|
end
|
575
573
|
end
|
576
574
|
|
577
|
-
default_values = column_defaults
|
578
|
-
stored_attrs = respond_to?(:stored_attributes) ? stored_attributes : {}
|
579
|
-
serialized_attrs = if defined?(ActiveRecord::Type::Serialized)
|
580
|
-
attrs = column_names.select { |c| type_for_attribute(c.to_s).class == ActiveRecord::Type::Serialized }
|
581
|
-
Hash[attrs.map { |a| [a, nil] }]
|
582
|
-
else
|
583
|
-
serialized_attributes
|
584
|
-
end
|
585
|
-
|
586
575
|
update_attrs = if record_timestamps && options[:timestamps]
|
587
576
|
if respond_to?(:timestamp_attributes_for_update, true)
|
588
577
|
send(:timestamp_attributes_for_update).map(&:to_sym)
|
@@ -608,12 +597,8 @@ class ActiveRecord::Base
|
|
608
597
|
update_attrs && update_attrs.include?(name.to_sym) &&
|
609
598
|
!model.send("#{name}_changed?")
|
610
599
|
nil
|
611
|
-
elsif stored_attrs.key?(name.to_sym) ||
|
612
|
-
serialized_attrs.key?(name.to_s) ||
|
613
|
-
default_values[name.to_s]
|
614
|
-
model.read_attribute(name.to_s)
|
615
600
|
else
|
616
|
-
model.
|
601
|
+
model.read_attribute(name.to_s)
|
617
602
|
end
|
618
603
|
end
|
619
604
|
end
|
@@ -640,7 +625,7 @@ class ActiveRecord::Base
|
|
640
625
|
end
|
641
626
|
# supports empty array
|
642
627
|
elsif args.last.is_a?( Array ) && args.last.empty?
|
643
|
-
return ActiveRecord::Import::Result.new([], 0, [])
|
628
|
+
return ActiveRecord::Import::Result.new([], 0, [], [])
|
644
629
|
# supports 2-element array and array
|
645
630
|
elsif args.size == 2 && args.first.is_a?( Array ) && args.last.is_a?( Array )
|
646
631
|
|
@@ -851,6 +836,19 @@ class ActiveRecord::Base
|
|
851
836
|
end
|
852
837
|
end
|
853
838
|
|
839
|
+
deserialize_value = lambda do |column, value|
|
840
|
+
column = columns_hash[column]
|
841
|
+
return value unless column
|
842
|
+
if respond_to?(:type_caster)
|
843
|
+
type = type_for_attribute(column.name)
|
844
|
+
type.deserialize(value)
|
845
|
+
elsif column.respond_to?(:type_cast_from_database)
|
846
|
+
column.type_cast_from_database(value)
|
847
|
+
else
|
848
|
+
value
|
849
|
+
end
|
850
|
+
end
|
851
|
+
|
854
852
|
if models.size == import_result.results.size
|
855
853
|
columns = Array(options[:returning])
|
856
854
|
single_column = "#{columns.first}=" if columns.size == 1
|
@@ -858,10 +856,12 @@ class ActiveRecord::Base
|
|
858
856
|
model = models[index]
|
859
857
|
|
860
858
|
if single_column
|
861
|
-
|
859
|
+
val = deserialize_value.call(columns.first, result)
|
860
|
+
model.send(single_column, val)
|
862
861
|
else
|
863
862
|
columns.each_with_index do |column, col_index|
|
864
|
-
|
863
|
+
val = deserialize_value.call(column, result[col_index])
|
864
|
+
model.send("#{column}=", val)
|
865
865
|
end
|
866
866
|
end
|
867
867
|
end
|
@@ -882,10 +882,12 @@ class ActiveRecord::Base
|
|
882
882
|
|
883
883
|
# Sync belongs_to association ids with foreign key field
|
884
884
|
def load_association_ids(model)
|
885
|
+
changed_columns = model.changed
|
885
886
|
association_reflections = model.class.reflect_on_all_associations(:belongs_to)
|
886
887
|
association_reflections.each do |association_reflection|
|
887
888
|
column_name = association_reflection.foreign_key
|
888
889
|
next if association_reflection.options[:polymorphic]
|
890
|
+
next if changed_columns.include?(column_name)
|
889
891
|
association = model.association(association_reflection.name)
|
890
892
|
association = association.target
|
891
893
|
next if association.blank? || model.public_send(column_name).present?
|
@@ -904,8 +906,9 @@ class ActiveRecord::Base
|
|
904
906
|
associated_objects_by_class = {}
|
905
907
|
models.each { |model| find_associated_objects_for_import(associated_objects_by_class, model) }
|
906
908
|
|
907
|
-
# :on_duplicate_key_update not supported for associations
|
909
|
+
# :on_duplicate_key_update and :returning not supported for associations
|
908
910
|
options.delete(:on_duplicate_key_update)
|
911
|
+
options.delete(:returning)
|
909
912
|
|
910
913
|
associated_objects_by_class.each_value do |associations|
|
911
914
|
associations.each_value do |associated_records|
|
@@ -964,7 +967,7 @@ class ActiveRecord::Base
|
|
964
967
|
elsif column
|
965
968
|
if respond_to?(:type_caster) # Rails 5.0 and higher
|
966
969
|
type = type_for_attribute(column.name)
|
967
|
-
val = type.type == :boolean ? type.cast(val) : type.serialize(val)
|
970
|
+
val = !type.respond_to?(:subtype) && type.type == :boolean ? type.cast(val) : type.serialize(val)
|
968
971
|
connection_memo.quote(val)
|
969
972
|
elsif column.respond_to?(:type_cast_from_user) # Rails 4.2
|
970
973
|
connection_memo.quote(column.type_cast_from_user(val), column)
|
@@ -973,9 +976,11 @@ class ActiveRecord::Base
|
|
973
976
|
val = serialized_attributes[column.name].dump(val)
|
974
977
|
end
|
975
978
|
# Fixes #443 to support binary (i.e. bytea) columns on PG
|
976
|
-
val = column.type_cast(val) unless column.type.to_sym == :binary
|
979
|
+
val = column.type_cast(val) unless column.type && column.type.to_sym == :binary
|
977
980
|
connection_memo.quote(val, column)
|
978
981
|
end
|
982
|
+
else
|
983
|
+
raise ArgumentError, "Number of values (#{arr.length}) exceeds number of columns (#{columns.length})"
|
979
984
|
end
|
980
985
|
end
|
981
986
|
"(#{my_values.join(',')})"
|