activerecord 4.1.8 → 4.2.11.3
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 +5 -5
- data/CHANGELOG.md +1165 -1591
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +15 -8
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations/alias_tracker.rb +3 -12
- data/lib/active_record/associations/association.rb +16 -4
- data/lib/active_record/associations/association_scope.rb +84 -43
- data/lib/active_record/associations/belongs_to_association.rb +28 -10
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -14
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +87 -30
- data/lib/active_record/associations/collection_proxy.rb +33 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +83 -22
- data/lib/active_record/associations/has_many_through_association.rb +49 -26
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +26 -12
- data/lib/active_record/associations/preloader/association.rb +14 -10
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/preloader.rb +37 -26
- data/lib/active_record/associations/singular_association.rb +17 -2
- data/lib/active_record/associations/through_association.rb +16 -12
- data/lib/active_record/associations.rb +158 -49
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +20 -12
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +107 -43
- data/lib/active_record/attribute_methods/primary_key.rb +7 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +16 -150
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -28
- data/lib/active_record/attribute_methods/write.rb +9 -24
- data/lib/active_record/attribute_methods.rb +57 -95
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +30 -12
- data/lib/active_record/base.rb +13 -24
- data/lib/active_record/callbacks.rb +6 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +85 -53
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +139 -57
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +271 -74
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
- data/lib/active_record/connection_adapters/abstract_adapter.rb +177 -60
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +295 -141
- data/lib/active_record/connection_adapters/column.rb +29 -240
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +17 -33
- data/lib/active_record/connection_adapters/mysql_adapter.rb +68 -145
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -385
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +134 -43
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +163 -40
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +10 -12
- data/lib/active_record/errors.rb +53 -30
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixtures.rb +62 -74
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locking/optimistic.rb +46 -26
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +79 -47
- data/lib/active_record/model_schema.rb +52 -58
- data/lib/active_record/nested_attributes.rb +18 -8
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +48 -27
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +19 -14
- data/lib/active_record/railties/databases.rake +55 -56
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +281 -117
- data/lib/active_record/relation/batches.rb +0 -1
- data/lib/active_record/relation/calculations.rb +41 -37
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +71 -48
- data/lib/active_record/relation/merger.rb +39 -29
- data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +42 -12
- data/lib/active_record/relation/query_methods.rb +130 -73
- data/lib/active_record/relation/spawn_methods.rb +10 -3
- data/lib/active_record/relation.rb +57 -25
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +59 -28
- data/lib/active_record/schema_migration.rb +5 -4
- data/lib/active_record/scoping/default.rb +6 -4
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +61 -8
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
- data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +54 -28
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +31 -0
- data/lib/active_record/type/date.rb +50 -0
- data/lib/active_record/type/date_time.rb +54 -0
- data/lib/active_record/type/decimal.rb +64 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/integer.rb +59 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +62 -0
- data/lib/active_record/type/string.rb +40 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +110 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +5 -3
- data/lib/active_record/validations/uniqueness.rb +24 -20
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record.rb +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +66 -11
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
data/lib/active_record/core.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
require 'thread'
|
1
2
|
require 'active_support/core_ext/hash/indifferent_access'
|
2
3
|
require 'active_support/core_ext/object/duplicable'
|
3
|
-
require '
|
4
|
+
require 'active_support/core_ext/string/filters'
|
4
5
|
|
5
6
|
module ActiveRecord
|
6
7
|
module Core
|
@@ -16,7 +17,6 @@ module ActiveRecord
|
|
16
17
|
mattr_accessor :logger, instance_writer: false
|
17
18
|
|
18
19
|
##
|
19
|
-
# :singleton-method:
|
20
20
|
# Contains the database configuration - as is typically stored in config/database.yml -
|
21
21
|
# as a Hash.
|
22
22
|
#
|
@@ -85,15 +85,17 @@ module ActiveRecord
|
|
85
85
|
mattr_accessor :dump_schema_after_migration, instance_writer: false
|
86
86
|
self.dump_schema_after_migration = true
|
87
87
|
|
88
|
-
# :nodoc:
|
89
88
|
mattr_accessor :maintain_test_schema, instance_accessor: false
|
90
89
|
|
91
90
|
def self.disable_implicit_join_references=(value)
|
92
|
-
ActiveSupport::Deprecation.warn(
|
93
|
-
|
91
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
92
|
+
Implicit join references were removed with Rails 4.1.
|
93
|
+
Make sure to remove this configuration because it does nothing.
|
94
|
+
MSG
|
94
95
|
end
|
95
96
|
|
96
97
|
class_attribute :default_connection_handler, instance_writer: false
|
98
|
+
class_attribute :find_by_statement_cache
|
97
99
|
|
98
100
|
def self.connection_handler
|
99
101
|
ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
|
@@ -107,7 +109,94 @@ module ActiveRecord
|
|
107
109
|
end
|
108
110
|
|
109
111
|
module ClassMethods
|
110
|
-
def
|
112
|
+
def allocate
|
113
|
+
define_attribute_methods
|
114
|
+
super
|
115
|
+
end
|
116
|
+
|
117
|
+
def initialize_find_by_cache # :nodoc:
|
118
|
+
self.find_by_statement_cache = {}.extend(Mutex_m)
|
119
|
+
end
|
120
|
+
|
121
|
+
def inherited(child_class) # :nodoc:
|
122
|
+
child_class.initialize_find_by_cache
|
123
|
+
super
|
124
|
+
end
|
125
|
+
|
126
|
+
def find(*ids) # :nodoc:
|
127
|
+
# We don't have cache keys for this stuff yet
|
128
|
+
return super unless ids.length == 1
|
129
|
+
# Allow symbols to super to maintain compatibility for deprecated finders until Rails 5
|
130
|
+
return super if ids.first.kind_of?(Symbol)
|
131
|
+
return super if block_given? ||
|
132
|
+
primary_key.nil? ||
|
133
|
+
default_scopes.any? ||
|
134
|
+
current_scope ||
|
135
|
+
columns_hash.include?(inheritance_column) ||
|
136
|
+
ids.first.kind_of?(Array)
|
137
|
+
|
138
|
+
id = ids.first
|
139
|
+
if ActiveRecord::Base === id
|
140
|
+
id = id.id
|
141
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
142
|
+
You are passing an instance of ActiveRecord::Base to `find`.
|
143
|
+
Please pass the id of the object by calling `.id`
|
144
|
+
MSG
|
145
|
+
end
|
146
|
+
key = primary_key
|
147
|
+
|
148
|
+
s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
|
149
|
+
find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
|
150
|
+
where(key => params.bind).limit(1)
|
151
|
+
}
|
152
|
+
}
|
153
|
+
record = s.execute([id], self, connection).first
|
154
|
+
unless record
|
155
|
+
raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
|
156
|
+
end
|
157
|
+
record
|
158
|
+
rescue RangeError
|
159
|
+
raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'"
|
160
|
+
end
|
161
|
+
|
162
|
+
def find_by(*args) # :nodoc:
|
163
|
+
return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any?
|
164
|
+
return super if default_scopes.any?
|
165
|
+
|
166
|
+
hash = args.first
|
167
|
+
|
168
|
+
return super if hash.values.any? { |v|
|
169
|
+
v.nil? || Array === v || Hash === v
|
170
|
+
}
|
171
|
+
|
172
|
+
# We can't cache Post.find_by(author: david) ...yet
|
173
|
+
return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
|
174
|
+
|
175
|
+
key = hash.keys
|
176
|
+
|
177
|
+
klass = self
|
178
|
+
s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
|
179
|
+
find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
|
180
|
+
wheres = key.each_with_object({}) { |param,o|
|
181
|
+
o[param] = params.bind
|
182
|
+
}
|
183
|
+
klass.where(wheres).limit(1)
|
184
|
+
}
|
185
|
+
}
|
186
|
+
begin
|
187
|
+
s.execute(hash.values, self, connection).first
|
188
|
+
rescue TypeError => e
|
189
|
+
raise ActiveRecord::StatementInvalid.new(e.message, e)
|
190
|
+
rescue RangeError
|
191
|
+
nil
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def find_by!(*args) # :nodoc:
|
196
|
+
find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}")
|
197
|
+
end
|
198
|
+
|
199
|
+
def initialize_generated_modules # :nodoc:
|
111
200
|
generated_association_methods
|
112
201
|
end
|
113
202
|
|
@@ -181,12 +270,8 @@ module ActiveRecord
|
|
181
270
|
# # Instantiates a single new object
|
182
271
|
# User.new(first_name: 'Jamie')
|
183
272
|
def initialize(attributes = nil, options = {})
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
@attributes = self.class.initialize_attributes(defaults)
|
188
|
-
@column_types_override = nil
|
189
|
-
@column_types = self.class.column_types
|
273
|
+
@attributes = self.class._default_attributes.dup
|
274
|
+
self.class.define_attribute_methods
|
190
275
|
|
191
276
|
init_internals
|
192
277
|
initialize_internals_callback
|
@@ -196,32 +281,35 @@ module ActiveRecord
|
|
196
281
|
init_attributes(attributes, options) if attributes
|
197
282
|
|
198
283
|
yield self if block_given?
|
199
|
-
|
284
|
+
_run_initialize_callbacks
|
200
285
|
end
|
201
286
|
|
202
|
-
# Initialize an empty model object from +coder+. +coder+
|
203
|
-
# the
|
204
|
-
#
|
287
|
+
# Initialize an empty model object from +coder+. +coder+ should be
|
288
|
+
# the result of previously encoding an Active Record model, using
|
289
|
+
# `encode_with`
|
205
290
|
#
|
206
291
|
# class Post < ActiveRecord::Base
|
207
292
|
# end
|
208
293
|
#
|
294
|
+
# old_post = Post.new(title: "hello world")
|
295
|
+
# coder = {}
|
296
|
+
# old_post.encode_with(coder)
|
297
|
+
#
|
209
298
|
# post = Post.allocate
|
210
|
-
# post.init_with(
|
299
|
+
# post.init_with(coder)
|
211
300
|
# post.title # => 'hello world'
|
212
301
|
def init_with(coder)
|
213
|
-
|
214
|
-
@
|
215
|
-
@column_types = self.class.column_types
|
302
|
+
coder = LegacyYamlAdapter.convert(self.class, coder)
|
303
|
+
@attributes = coder['attributes']
|
216
304
|
|
217
305
|
init_internals
|
218
306
|
|
219
|
-
@new_record =
|
307
|
+
@new_record = coder['new_record']
|
220
308
|
|
221
309
|
self.class.define_attribute_methods
|
222
310
|
|
223
|
-
|
224
|
-
|
311
|
+
_run_find_callbacks
|
312
|
+
_run_initialize_callbacks
|
225
313
|
|
226
314
|
self
|
227
315
|
end
|
@@ -254,17 +342,13 @@ module ActiveRecord
|
|
254
342
|
|
255
343
|
##
|
256
344
|
def initialize_dup(other) # :nodoc:
|
257
|
-
|
258
|
-
self.class.
|
259
|
-
|
260
|
-
@attributes = cloned_attributes
|
261
|
-
@attributes[self.class.primary_key] = nil
|
345
|
+
@attributes = @attributes.dup
|
346
|
+
@attributes.reset(self.class.primary_key)
|
262
347
|
|
263
|
-
|
348
|
+
_run_initialize_callbacks
|
264
349
|
|
265
350
|
@aggregation_cache = {}
|
266
351
|
@association_cache = {}
|
267
|
-
@attributes_cache = {}
|
268
352
|
|
269
353
|
@new_record = true
|
270
354
|
@destroyed = false
|
@@ -285,7 +369,11 @@ module ActiveRecord
|
|
285
369
|
# Post.new.encode_with(coder)
|
286
370
|
# coder # => {"attributes" => {"id" => nil, ... }}
|
287
371
|
def encode_with(coder)
|
288
|
-
|
372
|
+
# FIXME: Remove this when we better serialize attributes
|
373
|
+
coder['raw_attributes'] = attributes_before_type_cast
|
374
|
+
coder['attributes'] = @attributes
|
375
|
+
coder['new_record'] = new_record?
|
376
|
+
coder['active_record_yaml_version'] = 0
|
289
377
|
end
|
290
378
|
|
291
379
|
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
@@ -308,7 +396,11 @@ module ActiveRecord
|
|
308
396
|
# Delegates to id in order to allow two records of the same type and id to work with something like:
|
309
397
|
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
|
310
398
|
def hash
|
311
|
-
id
|
399
|
+
if id
|
400
|
+
id.hash
|
401
|
+
else
|
402
|
+
super
|
403
|
+
end
|
312
404
|
end
|
313
405
|
|
314
406
|
# Clone and freeze the attributes hash such that associations are still
|
@@ -364,21 +456,45 @@ module ActiveRecord
|
|
364
456
|
"#<#{self.class} #{inspection}>"
|
365
457
|
end
|
366
458
|
|
459
|
+
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from `pp record`
|
460
|
+
# when pp is required.
|
461
|
+
def pretty_print(pp)
|
462
|
+
return super if custom_inspect_method_defined?
|
463
|
+
pp.object_address_group(self) do
|
464
|
+
if defined?(@attributes) && @attributes
|
465
|
+
column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? }
|
466
|
+
pp.seplist(column_names, proc { pp.text ',' }) do |column_name|
|
467
|
+
column_value = read_attribute(column_name)
|
468
|
+
pp.breakable ' '
|
469
|
+
pp.group(1) do
|
470
|
+
pp.text column_name
|
471
|
+
pp.text ':'
|
472
|
+
pp.breakable
|
473
|
+
pp.pp column_value
|
474
|
+
end
|
475
|
+
end
|
476
|
+
else
|
477
|
+
pp.breakable ' '
|
478
|
+
pp.text 'not initialized'
|
479
|
+
end
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
367
483
|
# Returns a hash of the given methods with their names as keys and returned values as values.
|
368
484
|
def slice(*methods)
|
369
485
|
Hash[methods.map! { |method| [method, public_send(method)] }].with_indifferent_access
|
370
486
|
end
|
371
487
|
|
488
|
+
private
|
489
|
+
|
372
490
|
def set_transaction_state(state) # :nodoc:
|
373
491
|
@transaction_state = state
|
374
492
|
end
|
375
493
|
|
376
494
|
def has_transactional_callbacks? # :nodoc:
|
377
|
-
!_rollback_callbacks.empty? || !_commit_callbacks.empty?
|
495
|
+
!_rollback_callbacks.empty? || !_commit_callbacks.empty?
|
378
496
|
end
|
379
497
|
|
380
|
-
private
|
381
|
-
|
382
498
|
# Updates the attributes on this particular ActiveRecord object so that
|
383
499
|
# if it is associated with a transaction, then the state of the AR object
|
384
500
|
# will be updated to reflect the current state of the transaction
|
@@ -401,6 +517,8 @@ module ActiveRecord
|
|
401
517
|
end
|
402
518
|
|
403
519
|
def update_attributes_from_transaction_state(transaction_state, depth)
|
520
|
+
@reflects_state = [false] if depth == 0
|
521
|
+
|
404
522
|
if transaction_state && transaction_state.finalized? && !has_transactional_callbacks?
|
405
523
|
unless @reflects_state[depth]
|
406
524
|
restore_transaction_record_state if transaction_state.rolledback?
|
@@ -427,12 +545,8 @@ module ActiveRecord
|
|
427
545
|
end
|
428
546
|
|
429
547
|
def init_internals
|
430
|
-
pk = self.class.primary_key
|
431
|
-
@attributes[pk] = nil unless @attributes.key?(pk)
|
432
|
-
|
433
548
|
@aggregation_cache = {}
|
434
549
|
@association_cache = {}
|
435
|
-
@attributes_cache = {}
|
436
550
|
@readonly = false
|
437
551
|
@destroyed = false
|
438
552
|
@marked_for_destruction = false
|
@@ -441,7 +555,6 @@ module ActiveRecord
|
|
441
555
|
@txn = nil
|
442
556
|
@_start_transaction_state = {}
|
443
557
|
@transaction_state = nil
|
444
|
-
@reflects_state = [false]
|
445
558
|
end
|
446
559
|
|
447
560
|
def initialize_internals_callback
|
@@ -452,5 +565,15 @@ module ActiveRecord
|
|
452
565
|
def init_attributes(attributes, options)
|
453
566
|
assign_attributes(attributes)
|
454
567
|
end
|
568
|
+
|
569
|
+
def thaw
|
570
|
+
if frozen?
|
571
|
+
@attributes = @attributes.dup
|
572
|
+
end
|
573
|
+
end
|
574
|
+
|
575
|
+
def custom_inspect_method_defined?
|
576
|
+
self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
|
577
|
+
end
|
455
578
|
end
|
456
579
|
end
|
@@ -11,7 +11,7 @@ module ActiveRecord
|
|
11
11
|
# ==== Parameters
|
12
12
|
#
|
13
13
|
# * +id+ - The id of the object you wish to reset a counter on.
|
14
|
-
# * +counters+ - One or more association counters to reset
|
14
|
+
# * +counters+ - One or more association counters to reset. Association name or counter name can be given.
|
15
15
|
#
|
16
16
|
# ==== Examples
|
17
17
|
#
|
@@ -19,9 +19,14 @@ module ActiveRecord
|
|
19
19
|
# Post.reset_counters(1, :comments)
|
20
20
|
def reset_counters(id, *counters)
|
21
21
|
object = find(id)
|
22
|
-
counters.each do |
|
23
|
-
has_many_association = _reflect_on_association(
|
24
|
-
|
22
|
+
counters.each do |counter_association|
|
23
|
+
has_many_association = _reflect_on_association(counter_association)
|
24
|
+
unless has_many_association
|
25
|
+
has_many = reflect_on_all_associations(:has_many)
|
26
|
+
has_many_association = has_many.find { |association| association.counter_cache_column && association.counter_cache_column.to_sym == counter_association.to_sym }
|
27
|
+
counter_association = has_many_association.plural_name if has_many_association
|
28
|
+
end
|
29
|
+
raise ArgumentError, "'#{self.name}' has no association called '#{counter_association}'" unless has_many_association
|
25
30
|
|
26
31
|
if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection
|
27
32
|
has_many_association = has_many_association.through_reflection
|
@@ -29,11 +34,11 @@ module ActiveRecord
|
|
29
34
|
|
30
35
|
foreign_key = has_many_association.foreign_key.to_s
|
31
36
|
child_class = has_many_association.klass
|
32
|
-
reflection = child_class._reflections.values.find { |e|
|
37
|
+
reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
|
33
38
|
counter_name = reflection.counter_cache_column
|
34
39
|
|
35
40
|
stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
|
36
|
-
arel_table[counter_name] => object.send(
|
41
|
+
arel_table[counter_name] => object.send(counter_association).count(:all)
|
37
42
|
}, primary_key)
|
38
43
|
connection.update stmt
|
39
44
|
end
|
@@ -117,5 +122,54 @@ module ActiveRecord
|
|
117
122
|
update_counters(id, counter_name => -1)
|
118
123
|
end
|
119
124
|
end
|
125
|
+
|
126
|
+
protected
|
127
|
+
|
128
|
+
def actually_destroyed?
|
129
|
+
@_actually_destroyed
|
130
|
+
end
|
131
|
+
|
132
|
+
def clear_destroy_state
|
133
|
+
@_actually_destroyed = nil
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def _create_record(*)
|
139
|
+
id = super
|
140
|
+
|
141
|
+
each_counter_cached_associations do |association|
|
142
|
+
if send(association.reflection.name)
|
143
|
+
association.increment_counters
|
144
|
+
@_after_create_counter_called = true
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
id
|
149
|
+
end
|
150
|
+
|
151
|
+
def destroy_row
|
152
|
+
affected_rows = super
|
153
|
+
|
154
|
+
if affected_rows > 0
|
155
|
+
each_counter_cached_associations do |association|
|
156
|
+
foreign_key = association.reflection.foreign_key.to_sym
|
157
|
+
unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key
|
158
|
+
if send(association.reflection.name)
|
159
|
+
association.decrement_counters
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
affected_rows
|
166
|
+
end
|
167
|
+
|
168
|
+
def each_counter_cached_associations
|
169
|
+
_reflections.each do |name, reflection|
|
170
|
+
yield association(name.to_sym) if reflection.belongs_to? && reflection.counter_cache_column
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
120
174
|
end
|
121
175
|
end
|
data/lib/active_record/enum.rb
CHANGED
@@ -18,17 +18,18 @@ module ActiveRecord
|
|
18
18
|
# conversation.archived? # => true
|
19
19
|
# conversation.status # => "archived"
|
20
20
|
#
|
21
|
-
# # conversation.
|
21
|
+
# # conversation.status = 1
|
22
22
|
# conversation.status = "archived"
|
23
23
|
#
|
24
|
-
# # conversation.update! status: nil
|
25
24
|
# conversation.status = nil
|
26
25
|
# conversation.status.nil? # => true
|
27
26
|
# conversation.status # => nil
|
28
27
|
#
|
29
28
|
# Scopes based on the allowed values of the enum field will be provided
|
30
|
-
# as well. With the above example
|
31
|
-
#
|
29
|
+
# as well. With the above example:
|
30
|
+
#
|
31
|
+
# Conversation.active
|
32
|
+
# Conversation.archived
|
32
33
|
#
|
33
34
|
# You can set the default value from the database declaration, like:
|
34
35
|
#
|
@@ -68,7 +69,7 @@ module ActiveRecord
|
|
68
69
|
# Where conditions on an enum attribute must use the ordinal value of an enum.
|
69
70
|
module Enum
|
70
71
|
def self.extended(base) # :nodoc:
|
71
|
-
base.class_attribute(:defined_enums)
|
72
|
+
base.class_attribute(:defined_enums, instance_writer: false)
|
72
73
|
base.defined_enums = {}
|
73
74
|
end
|
74
75
|
|
@@ -138,19 +139,16 @@ module ActiveRecord
|
|
138
139
|
@_enum_methods_module ||= begin
|
139
140
|
mod = Module.new do
|
140
141
|
private
|
141
|
-
def save_changed_attribute(attr_name,
|
142
|
+
def save_changed_attribute(attr_name, old)
|
142
143
|
if (mapping = self.class.defined_enums[attr_name.to_s])
|
144
|
+
value = _read_attribute(attr_name)
|
143
145
|
if attribute_changed?(attr_name)
|
144
|
-
old = changed_attributes[attr_name]
|
145
|
-
|
146
146
|
if mapping[old] == value
|
147
|
-
|
147
|
+
clear_attribute_changes([attr_name])
|
148
148
|
end
|
149
149
|
else
|
150
|
-
old = clone_attribute_value(:read_attribute, attr_name)
|
151
|
-
|
152
150
|
if old != value
|
153
|
-
|
151
|
+
set_attribute_was(attr_name, mapping.key(old))
|
154
152
|
end
|
155
153
|
end
|
156
154
|
else
|
data/lib/active_record/errors.rb
CHANGED
@@ -30,17 +30,18 @@ module ActiveRecord
|
|
30
30
|
class SerializationTypeMismatch < ActiveRecordError
|
31
31
|
end
|
32
32
|
|
33
|
-
# Raised when adapter not specified on connection (or configuration file
|
34
|
-
# misses adapter field).
|
33
|
+
# Raised when adapter not specified on connection (or configuration file
|
34
|
+
# +config/database.yml+ misses adapter field).
|
35
35
|
class AdapterNotSpecified < ActiveRecordError
|
36
36
|
end
|
37
37
|
|
38
|
-
# Raised when Active Record cannot find database adapter specified in
|
38
|
+
# Raised when Active Record cannot find database adapter specified in
|
39
|
+
# +config/database.yml+ or programmatically.
|
39
40
|
class AdapterNotFound < ActiveRecordError
|
40
41
|
end
|
41
42
|
|
42
|
-
# Raised when connection to the database could not been established (for
|
43
|
-
# is given a nil object).
|
43
|
+
# Raised when connection to the database could not been established (for
|
44
|
+
# example when +connection=+ is given a nil object).
|
44
45
|
class ConnectionNotEstablished < ActiveRecordError
|
45
46
|
end
|
46
47
|
|
@@ -51,10 +52,29 @@ module ActiveRecord
|
|
51
52
|
# Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be
|
52
53
|
# saved because record is invalid.
|
53
54
|
class RecordNotSaved < ActiveRecordError
|
55
|
+
attr_reader :record
|
56
|
+
|
57
|
+
def initialize(message, record = nil)
|
58
|
+
@record = record
|
59
|
+
super(message)
|
60
|
+
end
|
54
61
|
end
|
55
62
|
|
56
63
|
# Raised by ActiveRecord::Base.destroy! when a call to destroy would return false.
|
64
|
+
#
|
65
|
+
# begin
|
66
|
+
# complex_operation_that_internally_calls_destroy!
|
67
|
+
# rescue ActiveRecord::RecordNotDestroyed => invalid
|
68
|
+
# puts invalid.record.errors
|
69
|
+
# end
|
70
|
+
#
|
57
71
|
class RecordNotDestroyed < ActiveRecordError
|
72
|
+
attr_reader :record
|
73
|
+
|
74
|
+
def initialize(message, record = nil)
|
75
|
+
@record = record
|
76
|
+
super(message)
|
77
|
+
end
|
58
78
|
end
|
59
79
|
|
60
80
|
# Superclass for all database execution errors.
|
@@ -82,35 +102,26 @@ module ActiveRecord
|
|
82
102
|
class InvalidForeignKey < WrappedDatabaseException
|
83
103
|
end
|
84
104
|
|
85
|
-
# Raised when number of bind variables in statement given to
|
86
|
-
# when using +find+ method)
|
87
|
-
#
|
105
|
+
# Raised when number of bind variables in statement given to +:condition+ key
|
106
|
+
# (for example, when using +find+ method) does not match number of expected
|
107
|
+
# values supplied.
|
88
108
|
#
|
89
|
-
# For example,
|
109
|
+
# For example, when there are two placeholders with only one value supplied:
|
90
110
|
#
|
91
111
|
# Location.where("lat = ? AND lng = ?", 53.7362)
|
92
|
-
#
|
93
|
-
# two placeholders are given but only one variable to fill them.
|
94
112
|
class PreparedStatementInvalid < ActiveRecordError
|
95
113
|
end
|
96
114
|
|
97
|
-
# Raised when a given database does not exist
|
98
|
-
class NoDatabaseError <
|
99
|
-
def initialize(message)
|
100
|
-
super extend_message(message)
|
101
|
-
end
|
102
|
-
|
103
|
-
# can be over written to add additional error information.
|
104
|
-
def extend_message(message)
|
105
|
-
message
|
106
|
-
end
|
115
|
+
# Raised when a given database does not exist.
|
116
|
+
class NoDatabaseError < StatementInvalid
|
107
117
|
end
|
108
118
|
|
109
119
|
# Raised on attempt to save stale record. Record is stale when it's being saved in another query after
|
110
120
|
# instantiation, for example, when two users edit the same wiki page and one starts editing and saves
|
111
121
|
# the page before the other.
|
112
122
|
#
|
113
|
-
# Read more about optimistic locking in ActiveRecord::Locking module
|
123
|
+
# Read more about optimistic locking in ActiveRecord::Locking module
|
124
|
+
# documentation.
|
114
125
|
class StaleObjectError < ActiveRecordError
|
115
126
|
attr_reader :record, :attempted_action
|
116
127
|
|
@@ -122,8 +133,9 @@ module ActiveRecord
|
|
122
133
|
|
123
134
|
end
|
124
135
|
|
125
|
-
# Raised when association is being configured improperly or
|
126
|
-
#
|
136
|
+
# Raised when association is being configured improperly or user tries to use
|
137
|
+
# offset and limit together with +has_many+ or +has_and_belongs_to_many+
|
138
|
+
# associations.
|
127
139
|
class ConfigurationError < ActiveRecordError
|
128
140
|
end
|
129
141
|
|
@@ -161,7 +173,8 @@ module ActiveRecord
|
|
161
173
|
class Rollback < ActiveRecordError
|
162
174
|
end
|
163
175
|
|
164
|
-
# Raised when attribute has a name reserved by Active Record (when attribute
|
176
|
+
# Raised when attribute has a name reserved by Active Record (when attribute
|
177
|
+
# has name of one of Active Record instance methods).
|
165
178
|
class DangerousAttributeError < ActiveRecordError
|
166
179
|
end
|
167
180
|
|
@@ -173,16 +186,17 @@ module ActiveRecord
|
|
173
186
|
def initialize(record, attribute)
|
174
187
|
@record = record
|
175
188
|
@attribute = attribute.to_s
|
176
|
-
super("unknown attribute
|
189
|
+
super("unknown attribute '#{attribute}' for #{@record.class}.")
|
177
190
|
end
|
178
191
|
|
179
192
|
end
|
180
193
|
|
181
194
|
# Raised when an error occurred while doing a mass assignment to an attribute through the
|
182
|
-
#
|
195
|
+
# +attributes=+ method. The exception has an +attribute+ property that is the name of the
|
183
196
|
# offending attribute.
|
184
197
|
class AttributeAssignmentError < ActiveRecordError
|
185
198
|
attr_reader :exception, :attribute
|
199
|
+
|
186
200
|
def initialize(message, exception, attribute)
|
187
201
|
super(message)
|
188
202
|
@exception = exception
|
@@ -195,6 +209,7 @@ module ActiveRecord
|
|
195
209
|
# objects, each corresponding to the error while assigning to an attribute.
|
196
210
|
class MultiparameterAssignmentErrors < ActiveRecordError
|
197
211
|
attr_reader :errors
|
212
|
+
|
198
213
|
def initialize(errors)
|
199
214
|
@errors = errors
|
200
215
|
end
|
@@ -204,11 +219,12 @@ module ActiveRecord
|
|
204
219
|
class UnknownPrimaryKey < ActiveRecordError
|
205
220
|
attr_reader :model
|
206
221
|
|
207
|
-
def initialize(model)
|
208
|
-
|
222
|
+
def initialize(model, description = nil)
|
223
|
+
message = "Unknown primary key for table #{model.table_name} in model #{model}."
|
224
|
+
message += "\n#{description}" if description
|
225
|
+
super(message)
|
209
226
|
@model = model
|
210
227
|
end
|
211
|
-
|
212
228
|
end
|
213
229
|
|
214
230
|
# Raised when a relation cannot be mutated because it's already loaded.
|
@@ -225,6 +241,13 @@ module ActiveRecord
|
|
225
241
|
class ImmutableRelation < ActiveRecordError
|
226
242
|
end
|
227
243
|
|
244
|
+
# TransactionIsolationError will be raised under the following conditions:
|
245
|
+
#
|
246
|
+
# * The adapter does not support setting the isolation level
|
247
|
+
# * You are joining an existing open transaction
|
248
|
+
# * You are creating a nested (savepoint) transaction
|
249
|
+
#
|
250
|
+
# The mysql, mysql2 and postgresql adapters support setting the transaction isolation level.
|
228
251
|
class TransactionIsolationError < ActiveRecordError
|
229
252
|
end
|
230
253
|
end
|
@@ -19,7 +19,7 @@ module ActiveRecord
|
|
19
19
|
# On the other hand, we want to monitor the performance of our real database
|
20
20
|
# queries, not the performance of the access to the query cache.
|
21
21
|
IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE)
|
22
|
-
EXPLAINED_SQLS = /\A\s*(select|update|delete|insert)\b/i
|
22
|
+
EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i
|
23
23
|
def ignore_payload?(payload)
|
24
24
|
payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) || payload[:sql] !~ EXPLAINED_SQLS
|
25
25
|
end
|