activerecord 5.2.0.rc1 → 5.2.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +75 -16
- data/README.rdoc +1 -1
- data/lib/active_record/associations/association.rb +4 -4
- data/lib/active_record/associations/association_scope.rb +6 -6
- data/lib/active_record/associations/belongs_to_association.rb +9 -1
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/has_one_association.rb +1 -0
- data/lib/active_record/associations/join_dependency.rb +2 -4
- data/lib/active_record/associations/preloader/association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +0 -5
- data/lib/active_record/attribute_methods.rb +19 -14
- data/lib/active_record/attribute_methods/dirty.rb +4 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +2 -2
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +2 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +40 -10
- data/lib/active_record/locking/optimistic.rb +27 -41
- data/lib/active_record/migration.rb +8 -2
- data/lib/active_record/model_schema.rb +1 -0
- data/lib/active_record/persistence.rb +60 -51
- data/lib/active_record/query_cache.rb +6 -6
- data/lib/active_record/railties/databases.rake +1 -1
- data/lib/active_record/reflection.rb +7 -4
- data/lib/active_record/relation/calculations.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +3 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +7 -5
- data/lib/active_record/relation/predicate_builder/range_handler.rb +4 -3
- data/lib/active_record/relation/query_attribute.rb +17 -0
- data/lib/active_record/validations/uniqueness.rb +1 -1
- metadata +10 -9
@@ -119,11 +119,11 @@ module ActiveRecord
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
-
def migrations_paths
|
122
|
+
def migrations_paths # :nodoc:
|
123
123
|
@config[:migrations_paths] || Migrator.migrations_paths
|
124
124
|
end
|
125
125
|
|
126
|
-
def migration_context
|
126
|
+
def migration_context # :nodoc:
|
127
127
|
MigrationContext.new(migrations_paths)
|
128
128
|
end
|
129
129
|
|
@@ -515,7 +515,7 @@ module ActiveRecord
|
|
515
515
|
s.gsub(/\s+(?:ASC|DESC)\b/i, "")
|
516
516
|
}.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
517
517
|
|
518
|
-
|
518
|
+
(order_columns << super).join(", ")
|
519
519
|
end
|
520
520
|
|
521
521
|
def strict_mode?
|
@@ -5,6 +5,7 @@ require "active_record/connection_adapters/postgresql/oid/bit"
|
|
5
5
|
require "active_record/connection_adapters/postgresql/oid/bit_varying"
|
6
6
|
require "active_record/connection_adapters/postgresql/oid/bytea"
|
7
7
|
require "active_record/connection_adapters/postgresql/oid/cidr"
|
8
|
+
require "active_record/connection_adapters/postgresql/oid/date"
|
8
9
|
require "active_record/connection_adapters/postgresql/oid/date_time"
|
9
10
|
require "active_record/connection_adapters/postgresql/oid/decimal"
|
10
11
|
require "active_record/connection_adapters/postgresql/oid/enum"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module PostgreSQL
|
6
|
+
module OID # :nodoc:
|
7
|
+
class Date < Type::Date # :nodoc:
|
8
|
+
def cast_value(value)
|
9
|
+
case value
|
10
|
+
when "infinity" then ::Float::INFINITY
|
11
|
+
when "-infinity" then -::Float::INFINITY
|
12
|
+
when / BC$/
|
13
|
+
astronomical_year = format("%04d", -value[/^\d+/].to_i + 1)
|
14
|
+
super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year))
|
15
|
+
else
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -107,7 +107,7 @@ module ActiveRecord
|
|
107
107
|
oid = row[4]
|
108
108
|
comment = row[5]
|
109
109
|
|
110
|
-
using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/).flatten
|
110
|
+
using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/m).flatten
|
111
111
|
|
112
112
|
orders = {}
|
113
113
|
opclasses = {}
|
@@ -583,7 +583,7 @@ module ActiveRecord
|
|
583
583
|
.gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
|
584
584
|
}.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
585
585
|
|
586
|
-
|
586
|
+
(order_columns << super).join(", ")
|
587
587
|
end
|
588
588
|
|
589
589
|
def update_table_definition(table_name, base) # :nodoc:
|
@@ -465,7 +465,7 @@ module ActiveRecord
|
|
465
465
|
register_class_with_limit m, "bit", OID::Bit
|
466
466
|
register_class_with_limit m, "varbit", OID::BitVarying
|
467
467
|
m.alias_type "timestamptz", "timestamp"
|
468
|
-
m.register_type "date",
|
468
|
+
m.register_type "date", OID::Date.new
|
469
469
|
|
470
470
|
m.register_type "money", OID::Money.new
|
471
471
|
m.register_type "bytea", OID::Bytea.new
|
@@ -837,6 +837,7 @@ module ActiveRecord
|
|
837
837
|
ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
|
838
838
|
ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
|
839
839
|
ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
|
840
|
+
ActiveRecord::Type.register(:date, OID::Date, adapter: :postgresql)
|
840
841
|
ActiveRecord::Type.register(:datetime, OID::DateTime, adapter: :postgresql)
|
841
842
|
ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
|
842
843
|
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
|
@@ -104,21 +104,47 @@ module ActiveRecord
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
-
# Set this to true if this is an abstract class (see
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
107
|
+
# Set this to +true+ if this is an abstract class (see
|
108
|
+
# <tt>abstract_class?</tt>).
|
109
|
+
# If you are using inheritance with Active Record and don't want a class
|
110
|
+
# to be considered as part of the STI hierarchy, you must set this to
|
111
|
+
# true.
|
112
|
+
# +ApplicationRecord+, for example, is generated as an abstract class.
|
111
113
|
#
|
112
|
-
#
|
114
|
+
# Consider the following default behaviour:
|
115
|
+
#
|
116
|
+
# Shape = Class.new(ActiveRecord::Base)
|
117
|
+
# Polygon = Class.new(Shape)
|
118
|
+
# Square = Class.new(Polygon)
|
119
|
+
#
|
120
|
+
# Shape.table_name # => "shapes"
|
121
|
+
# Polygon.table_name # => "shapes"
|
122
|
+
# Square.table_name # => "shapes"
|
123
|
+
# Shape.create! # => #<Shape id: 1, type: nil>
|
124
|
+
# Polygon.create! # => #<Polygon id: 2, type: "Polygon">
|
125
|
+
# Square.create! # => #<Square id: 3, type: "Square">
|
126
|
+
#
|
127
|
+
# However, when using <tt>abstract_class</tt>, +Shape+ is omitted from
|
128
|
+
# the hierarchy:
|
129
|
+
#
|
130
|
+
# class Shape < ActiveRecord::Base
|
113
131
|
# self.abstract_class = true
|
114
132
|
# end
|
115
|
-
#
|
116
|
-
#
|
117
|
-
# end
|
118
|
-
#
|
133
|
+
# Polygon = Class.new(Shape)
|
134
|
+
# Square = Class.new(Polygon)
|
119
135
|
#
|
120
|
-
#
|
136
|
+
# Shape.table_name # => nil
|
137
|
+
# Polygon.table_name # => "polygons"
|
138
|
+
# Square.table_name # => "polygons"
|
139
|
+
# Shape.create! # => NotImplementedError: Shape is an abstract class and cannot be instantiated.
|
140
|
+
# Polygon.create! # => #<Polygon id: 1, type: nil>
|
141
|
+
# Square.create! # => #<Square id: 2, type: "Square">
|
121
142
|
#
|
143
|
+
# Note that in the above example, to disallow the creation of a plain
|
144
|
+
# +Polygon+, you should use <tt>validates :type, presence: true</tt>,
|
145
|
+
# instead of setting it as an abstract class. This way, +Polygon+ will
|
146
|
+
# stay in the hierarchy, and Active Record will continue to correctly
|
147
|
+
# derive the table name.
|
122
148
|
attr_accessor :abstract_class
|
123
149
|
|
124
150
|
# Returns whether this class is an abstract class or not.
|
@@ -130,6 +156,10 @@ module ActiveRecord
|
|
130
156
|
store_full_sti_class ? name : name.demodulize
|
131
157
|
end
|
132
158
|
|
159
|
+
def polymorphic_name
|
160
|
+
base_class.name
|
161
|
+
end
|
162
|
+
|
133
163
|
def inherited(subclass)
|
134
164
|
subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
|
135
165
|
super
|
@@ -61,13 +61,6 @@ module ActiveRecord
|
|
61
61
|
end
|
62
62
|
|
63
63
|
private
|
64
|
-
|
65
|
-
def increment_lock
|
66
|
-
lock_col = self.class.locking_column
|
67
|
-
previous_lock_value = send(lock_col)
|
68
|
-
send("#{lock_col}=", previous_lock_value + 1)
|
69
|
-
end
|
70
|
-
|
71
64
|
def _create_record(attribute_names = self.attribute_names, *)
|
72
65
|
if locking_enabled?
|
73
66
|
# We always want to persist the locking version, even if we don't detect
|
@@ -77,63 +70,56 @@ module ActiveRecord
|
|
77
70
|
super
|
78
71
|
end
|
79
72
|
|
80
|
-
def
|
73
|
+
def _touch_row(attribute_names, time)
|
74
|
+
super
|
75
|
+
ensure
|
76
|
+
clear_attribute_change(self.class.locking_column) if locking_enabled?
|
77
|
+
end
|
78
|
+
|
79
|
+
def _update_row(attribute_names, attempted_action = "update")
|
81
80
|
return super unless locking_enabled?
|
82
|
-
return 0 if attribute_names.empty?
|
83
81
|
|
84
82
|
begin
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
increment_lock
|
90
|
-
|
91
|
-
attribute_names.push(lock_col)
|
83
|
+
locking_column = self.class.locking_column
|
84
|
+
previous_lock_value = read_attribute_before_type_cast(locking_column)
|
85
|
+
attribute_names << locking_column
|
92
86
|
|
93
|
-
|
87
|
+
self[locking_column] += 1
|
94
88
|
|
95
|
-
affected_rows =
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
attributes_for_update(attribute_names).map do |name|
|
100
|
-
[name, _read_attribute(name)]
|
101
|
-
end.to_h
|
89
|
+
affected_rows = self.class._update_record(
|
90
|
+
attributes_with_values(attribute_names),
|
91
|
+
self.class.primary_key => id_in_database,
|
92
|
+
locking_column => previous_lock_value
|
102
93
|
)
|
103
94
|
|
104
|
-
|
105
|
-
raise ActiveRecord::StaleObjectError.new(self,
|
95
|
+
if affected_rows != 1
|
96
|
+
raise ActiveRecord::StaleObjectError.new(self, attempted_action)
|
106
97
|
end
|
107
98
|
|
108
99
|
affected_rows
|
109
100
|
|
110
101
|
# If something went wrong, revert the locking_column value.
|
111
102
|
rescue Exception
|
112
|
-
|
113
|
-
|
103
|
+
self[locking_column] = previous_lock_value.to_i
|
114
104
|
raise
|
115
105
|
end
|
116
106
|
end
|
117
107
|
|
118
108
|
def destroy_row
|
119
|
-
|
120
|
-
|
121
|
-
if locking_enabled? && affected_rows != 1
|
122
|
-
raise ActiveRecord::StaleObjectError.new(self, "destroy")
|
123
|
-
end
|
109
|
+
return super unless locking_enabled?
|
124
110
|
|
125
|
-
|
126
|
-
end
|
111
|
+
locking_column = self.class.locking_column
|
127
112
|
|
128
|
-
|
129
|
-
|
113
|
+
affected_rows = self.class._delete_record(
|
114
|
+
self.class.primary_key => id_in_database,
|
115
|
+
locking_column => read_attribute_before_type_cast(locking_column)
|
116
|
+
)
|
130
117
|
|
131
|
-
if
|
132
|
-
|
133
|
-
relation = relation.where(locking_column => read_attribute_before_type_cast(locking_column))
|
118
|
+
if affected_rows != 1
|
119
|
+
raise ActiveRecord::StaleObjectError.new(self, "destroy")
|
134
120
|
end
|
135
121
|
|
136
|
-
|
122
|
+
affected_rows
|
137
123
|
end
|
138
124
|
|
139
125
|
module ClassMethods
|
@@ -140,6 +140,7 @@ module ActiveRecord
|
|
140
140
|
|
141
141
|
class ConcurrentMigrationError < MigrationError #:nodoc:
|
142
142
|
DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running.".freeze
|
143
|
+
RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock".freeze
|
143
144
|
|
144
145
|
def initialize(message = DEFAULT_MESSAGE)
|
145
146
|
super
|
@@ -1355,12 +1356,17 @@ module ActiveRecord
|
|
1355
1356
|
|
1356
1357
|
def with_advisory_lock
|
1357
1358
|
lock_id = generate_migrator_advisory_lock_id
|
1358
|
-
|
1359
|
+
connection = Base.connection
|
1360
|
+
got_lock = connection.get_advisory_lock(lock_id)
|
1359
1361
|
raise ConcurrentMigrationError unless got_lock
|
1360
1362
|
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
1361
1363
|
yield
|
1362
1364
|
ensure
|
1363
|
-
|
1365
|
+
if got_lock && !connection.release_advisory_lock(lock_id)
|
1366
|
+
raise ConcurrentMigrationError.new(
|
1367
|
+
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
1368
|
+
)
|
1369
|
+
end
|
1364
1370
|
end
|
1365
1371
|
|
1366
1372
|
MIGRATOR_SALT = 2053462845
|
@@ -169,12 +169,11 @@ module ActiveRecord
|
|
169
169
|
primary_key_value = nil
|
170
170
|
|
171
171
|
if primary_key && Hash === values
|
172
|
-
|
173
|
-
primary_key_value = values[arel_primary_key]
|
172
|
+
primary_key_value = values[primary_key]
|
174
173
|
|
175
174
|
if !primary_key_value && prefetch_primary_key?
|
176
175
|
primary_key_value = next_sequence_value
|
177
|
-
values[
|
176
|
+
values[primary_key] = primary_key_value
|
178
177
|
end
|
179
178
|
end
|
180
179
|
|
@@ -188,15 +187,26 @@ module ActiveRecord
|
|
188
187
|
connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
|
189
188
|
end
|
190
189
|
|
191
|
-
def _update_record(values,
|
192
|
-
|
190
|
+
def _update_record(values, constraints) # :nodoc:
|
191
|
+
constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
|
192
|
+
|
193
193
|
um = arel_table.where(
|
194
|
-
|
194
|
+
constraints.reduce(&:and)
|
195
195
|
).compile_update(_substitute_values(values), primary_key)
|
196
196
|
|
197
197
|
connection.update(um, "#{self} Update")
|
198
198
|
end
|
199
199
|
|
200
|
+
def _delete_record(constraints) # :nodoc:
|
201
|
+
constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
|
202
|
+
|
203
|
+
dm = Arel::DeleteManager.new
|
204
|
+
dm.from(arel_table)
|
205
|
+
dm.wheres = constraints
|
206
|
+
|
207
|
+
connection.delete(dm, "#{self} Destroy")
|
208
|
+
end
|
209
|
+
|
200
210
|
private
|
201
211
|
# Called by +instantiate+ to decide which class to use for a new
|
202
212
|
# record instance.
|
@@ -208,8 +218,9 @@ module ActiveRecord
|
|
208
218
|
end
|
209
219
|
|
210
220
|
def _substitute_values(values)
|
211
|
-
values.map do |
|
212
|
-
|
221
|
+
values.map do |name, value|
|
222
|
+
attr = arel_attribute(name)
|
223
|
+
bind = predicate_builder.build_bind_attribute(name, value)
|
213
224
|
[attr, bind]
|
214
225
|
end
|
215
226
|
end
|
@@ -310,7 +321,7 @@ module ActiveRecord
|
|
310
321
|
# callbacks or any <tt>:dependent</tt> association
|
311
322
|
# options, use <tt>#destroy</tt>.
|
312
323
|
def delete
|
313
|
-
|
324
|
+
_delete_row if persisted?
|
314
325
|
@destroyed = true
|
315
326
|
freeze
|
316
327
|
end
|
@@ -363,6 +374,7 @@ module ActiveRecord
|
|
363
374
|
became.send(:initialize)
|
364
375
|
became.instance_variable_set("@attributes", @attributes)
|
365
376
|
became.instance_variable_set("@mutations_from_database", @mutations_from_database) if defined?(@mutations_from_database)
|
377
|
+
became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
|
366
378
|
became.instance_variable_set("@new_record", new_record?)
|
367
379
|
became.instance_variable_set("@destroyed", destroyed?)
|
368
380
|
became.errors.copy!(errors)
|
@@ -461,13 +473,16 @@ module ActiveRecord
|
|
461
473
|
verify_readonly_attribute(key.to_s)
|
462
474
|
end
|
463
475
|
|
464
|
-
|
476
|
+
affected_rows = self.class._update_record(
|
477
|
+
attributes,
|
478
|
+
self.class.primary_key => id_in_database
|
479
|
+
)
|
465
480
|
|
466
481
|
attributes.each do |k, v|
|
467
482
|
write_attribute_without_type_cast(k, v)
|
468
483
|
end
|
469
484
|
|
470
|
-
|
485
|
+
affected_rows == 1
|
471
486
|
end
|
472
487
|
|
473
488
|
# Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
|
@@ -640,35 +655,12 @@ module ActiveRecord
|
|
640
655
|
MSG
|
641
656
|
end
|
642
657
|
|
643
|
-
|
644
|
-
|
645
|
-
attributes.concat(names)
|
646
|
-
|
647
|
-
unless attributes.empty?
|
648
|
-
changes = {}
|
649
|
-
|
650
|
-
attributes.each do |column|
|
651
|
-
column = column.to_s
|
652
|
-
changes[column] = write_attribute(column, time)
|
653
|
-
end
|
654
|
-
|
655
|
-
scope = _relation_for_itself
|
656
|
-
|
657
|
-
if locking_enabled?
|
658
|
-
locking_column = self.class.locking_column
|
659
|
-
scope = scope.where(locking_column => read_attribute_before_type_cast(locking_column))
|
660
|
-
changes[locking_column] = increment_lock
|
661
|
-
end
|
662
|
-
|
663
|
-
clear_attribute_changes(changes.keys)
|
664
|
-
result = scope.update_all(changes) == 1
|
665
|
-
|
666
|
-
if !result && locking_enabled?
|
667
|
-
raise ActiveRecord::StaleObjectError.new(self, "touch")
|
668
|
-
end
|
658
|
+
attribute_names = timestamp_attributes_for_update_in_model
|
659
|
+
attribute_names.concat(names)
|
669
660
|
|
670
|
-
|
671
|
-
|
661
|
+
unless attribute_names.empty?
|
662
|
+
affected_rows = _touch_row(attribute_names, time)
|
663
|
+
@_trigger_update_callback = affected_rows == 1
|
672
664
|
else
|
673
665
|
true
|
674
666
|
end
|
@@ -681,15 +673,29 @@ module ActiveRecord
|
|
681
673
|
end
|
682
674
|
|
683
675
|
def destroy_row
|
684
|
-
|
676
|
+
_delete_row
|
685
677
|
end
|
686
678
|
|
687
|
-
def
|
688
|
-
|
679
|
+
def _delete_row
|
680
|
+
self.class._delete_record(self.class.primary_key => id_in_database)
|
689
681
|
end
|
690
682
|
|
691
|
-
def
|
692
|
-
|
683
|
+
def _touch_row(attribute_names, time)
|
684
|
+
time ||= current_time_from_proper_timezone
|
685
|
+
|
686
|
+
attribute_names.each do |attr_name|
|
687
|
+
write_attribute(attr_name, time)
|
688
|
+
clear_attribute_change(attr_name)
|
689
|
+
end
|
690
|
+
|
691
|
+
_update_row(attribute_names, "touch")
|
692
|
+
end
|
693
|
+
|
694
|
+
def _update_row(attribute_names, attempted_action = "update")
|
695
|
+
self.class._update_record(
|
696
|
+
attributes_with_values(attribute_names),
|
697
|
+
self.class.primary_key => id_in_database
|
698
|
+
)
|
693
699
|
end
|
694
700
|
|
695
701
|
def create_or_update(*args, &block)
|
@@ -702,24 +708,27 @@ module ActiveRecord
|
|
702
708
|
# Updates the associated record with values matching those of the instance attributes.
|
703
709
|
# Returns the number of affected rows.
|
704
710
|
def _update_record(attribute_names = self.attribute_names)
|
705
|
-
|
706
|
-
|
707
|
-
|
711
|
+
attribute_names &= self.class.column_names
|
712
|
+
attribute_names = attributes_for_update(attribute_names)
|
713
|
+
|
714
|
+
if attribute_names.empty?
|
715
|
+
affected_rows = 0
|
708
716
|
@_trigger_update_callback = true
|
709
717
|
else
|
710
|
-
|
711
|
-
@_trigger_update_callback =
|
718
|
+
affected_rows = _update_row(attribute_names)
|
719
|
+
@_trigger_update_callback = affected_rows == 1
|
712
720
|
end
|
713
721
|
|
714
722
|
yield(self) if block_given?
|
715
723
|
|
716
|
-
|
724
|
+
affected_rows
|
717
725
|
end
|
718
726
|
|
719
727
|
# Creates a record with values matching those of the instance attributes
|
720
728
|
# and returns its id.
|
721
729
|
def _create_record(attribute_names = self.attribute_names)
|
722
|
-
|
730
|
+
attribute_names &= self.class.column_names
|
731
|
+
attributes_values = attributes_with_values_for_create(attribute_names)
|
723
732
|
|
724
733
|
new_id = self.class._insert_record(attributes_values)
|
725
734
|
self.id ||= new_id if self.class.primary_key
|