activerecord 3.2.13 → 3.2.14.rc1

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.

Files changed (37) hide show
  1. data/CHANGELOG.md +148 -2
  2. data/lib/active_record/associations/association.rb +9 -3
  3. data/lib/active_record/associations/belongs_to_association.rb +1 -1
  4. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +2 -1
  5. data/lib/active_record/associations/builder/belongs_to.rb +4 -1
  6. data/lib/active_record/associations/builder/belongs_to.rb.orig +95 -0
  7. data/lib/active_record/associations/collection_association.rb +1 -1
  8. data/lib/active_record/associations/has_many_association.rb +1 -2
  9. data/lib/active_record/associations/has_many_association.rb.orig +116 -0
  10. data/lib/active_record/associations/join_dependency.rb +1 -1
  11. data/lib/active_record/associations/join_dependency/join_association.rb +6 -1
  12. data/lib/active_record/associations/preloader/through_association.rb +1 -2
  13. data/lib/active_record/associations/through_association.rb +1 -1
  14. data/lib/active_record/autosave_association.rb +7 -12
  15. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -2
  16. data/lib/active_record/connection_adapters/abstract/schema_statements.rb.orig +619 -0
  17. data/lib/active_record/connection_adapters/connection_specification.rb.orig +124 -0
  18. data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -3
  19. data/lib/active_record/connection_adapters/postgresql/cast.rb.orig +136 -0
  20. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb.orig +485 -0
  21. data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -3
  22. data/lib/active_record/core.rb.orig +452 -0
  23. data/lib/active_record/explain_subscriber.rb +1 -1
  24. data/lib/active_record/model_schema.rb +4 -2
  25. data/lib/active_record/nested_attributes.rb +41 -17
  26. data/lib/active_record/railtie.rb +6 -7
  27. data/lib/active_record/railties/databases.rake +2 -1
  28. data/lib/active_record/relation/calculations.rb +5 -6
  29. data/lib/active_record/relation/calculations.rb.orig +378 -0
  30. data/lib/active_record/relation/finder_methods.rb +1 -0
  31. data/lib/active_record/relation/finder_methods.rb.orig +405 -0
  32. data/lib/active_record/relation/spawn_methods.rb +34 -3
  33. data/lib/active_record/store.rb +1 -1
  34. data/lib/active_record/version.rb +2 -2
  35. data/lib/rails/generators/active_record/observer/observer_generator.rb.orig +15 -0
  36. metadata +117 -70
  37. checksums.yaml +0 -7
@@ -142,7 +142,7 @@ module ActiveRecord
142
142
  when NilClass
143
143
  nil
144
144
  # Numeric types
145
- when /\A\(?(-?\d+(\.\d*)?\)?)\z/
145
+ when /\A\(?(-?\d+(\.\d*)?\)?(::bigint)?)\z/
146
146
  $1
147
147
  # Character types
148
148
  when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
@@ -1144,7 +1144,9 @@ module ActiveRecord
1144
1144
  UNIQUE_VIOLATION = "23505"
1145
1145
 
1146
1146
  def translate_exception(exception, message)
1147
- case exception.result.error_field(PGresult::PG_DIAG_SQLSTATE)
1147
+ return exception unless exception.respond_to?(:result)
1148
+
1149
+ case exception.result.try(:error_field, PGresult::PG_DIAG_SQLSTATE)
1148
1150
  when UNIQUE_VIOLATION
1149
1151
  RecordNotUnique.new(message, exception)
1150
1152
  when FOREIGN_KEY_VIOLATION
@@ -1177,7 +1179,11 @@ module ActiveRecord
1177
1179
  # prepared statements whose return value may have changed is
1178
1180
  # FEATURE_NOT_SUPPORTED. Check here for more details:
1179
1181
  # http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
1180
- code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
1182
+ begin
1183
+ code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
1184
+ rescue
1185
+ raise e
1186
+ end
1181
1187
  if FEATURE_NOT_SUPPORTED == code
1182
1188
  @statements.delete sql_key(sql)
1183
1189
  retry
@@ -0,0 +1,452 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'active_support/core_ext/object/duplicable'
3
+ require 'thread'
4
+
5
+ module ActiveRecord
6
+ module Core
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ ##
11
+ # :singleton-method:
12
+ #
13
+ # Accepts a logger conforming to the interface of Log4r which is then
14
+ # passed on to any new database connections made and which can be
15
+ # retrieved on both a class and instance level by calling +logger+.
16
+ mattr_accessor :logger, instance_writer: false
17
+
18
+ ##
19
+ # :singleton-method:
20
+ # Contains the database configuration - as is typically stored in config/database.yml -
21
+ # as a Hash.
22
+ #
23
+ # For example, the following database.yml...
24
+ #
25
+ # development:
26
+ # adapter: sqlite3
27
+ # database: db/development.sqlite3
28
+ #
29
+ # production:
30
+ # adapter: sqlite3
31
+ # database: db/production.sqlite3
32
+ #
33
+ # ...would result in ActiveRecord::Base.configurations to look like this:
34
+ #
35
+ # {
36
+ # 'development' => {
37
+ # 'adapter' => 'sqlite3',
38
+ # 'database' => 'db/development.sqlite3'
39
+ # },
40
+ # 'production' => {
41
+ # 'adapter' => 'sqlite3',
42
+ # 'database' => 'db/production.sqlite3'
43
+ # }
44
+ # }
45
+ mattr_accessor :configurations, instance_writer: false
46
+ self.configurations = {}
47
+
48
+ ##
49
+ # :singleton-method:
50
+ # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
51
+ # dates and times from the database. This is set to :utc by default.
52
+ mattr_accessor :default_timezone, instance_writer: false
53
+ self.default_timezone = :utc
54
+
55
+ ##
56
+ # :singleton-method:
57
+ # Specifies the format to use when dumping the database schema with Rails'
58
+ # Rakefile. If :sql, the schema is dumped as (potentially database-
59
+ # specific) SQL statements. If :ruby, the schema is dumped as an
60
+ # ActiveRecord::Schema file which can be loaded into any database that
61
+ # supports migrations. Use :ruby if you want to have different database
62
+ # adapters for, e.g., your development and test environments.
63
+ mattr_accessor :schema_format, instance_writer: false
64
+ self.schema_format = :ruby
65
+
66
+ ##
67
+ # :singleton-method:
68
+ # Specify whether or not to use timestamps for migration versions
69
+ mattr_accessor :timestamped_migrations, instance_writer: false
70
+ self.timestamped_migrations = true
71
+
72
+ <<<<<<< HEAD
73
+ ##
74
+ # :singleton-method:
75
+ # Disable implicit join references. This feature was deprecated with Rails 4.
76
+ # If you don't make use of implicit references but still see deprecation warnings
77
+ # you can disable the feature entirely. This will be the default with Rails 4.1.
78
+ mattr_accessor :disable_implicit_join_references, instance_writer: false
79
+ self.disable_implicit_join_references = false
80
+
81
+ class_attribute :connection_handler, instance_writer: false
82
+ self.connection_handler = ConnectionAdapters::ConnectionHandler.new
83
+ =======
84
+ class_attribute :default_connection_handler, instance_writer: false
85
+
86
+ def self.connection_handler
87
+ Thread.current[:active_record_connection_handler] || self.default_connection_handler
88
+ end
89
+
90
+ def self.connection_handler=(handler)
91
+ Thread.current[:active_record_connection_handler] = handler
92
+ end
93
+
94
+ self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
95
+ >>>>>>> SamSaffron/master
96
+ end
97
+
98
+ module ClassMethods
99
+ def inherited(child_class) #:nodoc:
100
+ child_class.initialize_generated_modules
101
+ super
102
+ end
103
+
104
+ def initialize_generated_modules
105
+ @attribute_methods_mutex = Mutex.new
106
+
107
+ # force attribute methods to be higher in inheritance hierarchy than other generated methods
108
+ generated_attribute_methods.const_set(:AttrNames, Module.new {
109
+ def self.const_missing(name)
110
+ const_set(name, [name.to_s.sub(/ATTR_/, '')].pack('h*').freeze)
111
+ end
112
+ })
113
+
114
+ generated_feature_methods
115
+ end
116
+
117
+ def generated_feature_methods
118
+ @generated_feature_methods ||= begin
119
+ mod = const_set(:GeneratedFeatureMethods, Module.new)
120
+ include mod
121
+ mod
122
+ end
123
+ end
124
+
125
+ # Returns a string like 'Post(id:integer, title:string, body:text)'
126
+ def inspect
127
+ if self == Base
128
+ super
129
+ elsif abstract_class?
130
+ "#{super}(abstract)"
131
+ elsif table_exists?
132
+ attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', '
133
+ "#{super}(#{attr_list})"
134
+ else
135
+ "#{super}(Table doesn't exist)"
136
+ end
137
+ end
138
+
139
+ # Overwrite the default class equality method to provide support for association proxies.
140
+ def ===(object)
141
+ object.is_a?(self)
142
+ end
143
+
144
+ # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
145
+ #
146
+ # class Post < ActiveRecord::Base
147
+ # scope :published_and_commented, published.and(self.arel_table[:comments_count].gt(0))
148
+ # end
149
+ def arel_table
150
+ @arel_table ||= Arel::Table.new(table_name, arel_engine)
151
+ end
152
+
153
+ # Returns the Arel engine.
154
+ def arel_engine
155
+ @arel_engine ||= begin
156
+ if Base == self || connection_handler.retrieve_connection_pool(self)
157
+ self
158
+ else
159
+ superclass.arel_engine
160
+ end
161
+ end
162
+ end
163
+
164
+ private
165
+
166
+ def relation #:nodoc:
167
+ relation = Relation.new(self, arel_table)
168
+
169
+ if finder_needs_type_condition?
170
+ relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
171
+ else
172
+ relation
173
+ end
174
+ end
175
+ end
176
+
177
+ # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
178
+ # attributes but not yet saved (pass a hash with key names matching the associated table column names).
179
+ # In both instances, valid attribute keys are determined by the column names of the associated table --
180
+ # hence you can't have attributes that aren't part of the table columns.
181
+ #
182
+ # ==== Example:
183
+ # # Instantiates a single new object
184
+ # User.new(first_name: 'Jamie')
185
+ def initialize(attributes = nil)
186
+ defaults = self.class.column_defaults.dup
187
+ defaults.each { |k, v| defaults[k] = v.dup if v.duplicable? }
188
+
189
+ @attributes = self.class.initialize_attributes(defaults)
190
+ @columns_hash = self.class.column_types.dup
191
+
192
+ init_internals
193
+ ensure_proper_type
194
+ populate_with_current_scope_attributes
195
+
196
+ assign_attributes(attributes) if attributes
197
+
198
+ yield self if block_given?
199
+ run_callbacks :initialize unless _initialize_callbacks.empty?
200
+ end
201
+
202
+ # Initialize an empty model object from +coder+. +coder+ must contain
203
+ # the attributes necessary for initializing an empty model object. For
204
+ # example:
205
+ #
206
+ # class Post < ActiveRecord::Base
207
+ # end
208
+ #
209
+ # post = Post.allocate
210
+ # post.init_with('attributes' => { 'title' => 'hello world' })
211
+ # post.title # => 'hello world'
212
+ def init_with(coder)
213
+ @attributes = self.class.initialize_attributes(coder['attributes'])
214
+ @columns_hash = self.class.column_types.merge(coder['column_types'] || {})
215
+
216
+ init_internals
217
+
218
+ @new_record = false
219
+
220
+ run_callbacks :find
221
+ run_callbacks :initialize
222
+
223
+ self
224
+ end
225
+
226
+ ##
227
+ # :method: clone
228
+ # Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied.
229
+ # That means that modifying attributes of the clone will modify the original, since they will both point to the
230
+ # same attributes hash. If you need a copy of your attributes hash, please use the #dup method.
231
+ #
232
+ # user = User.first
233
+ # new_user = user.clone
234
+ # user.name # => "Bob"
235
+ # new_user.name = "Joe"
236
+ # user.name # => "Joe"
237
+ #
238
+ # user.object_id == new_user.object_id # => false
239
+ # user.name.object_id == new_user.name.object_id # => true
240
+ #
241
+ # user.name.object_id == user.dup.name.object_id # => false
242
+
243
+ ##
244
+ # :method: dup
245
+ # Duped objects have no id assigned and are treated as new records. Note
246
+ # that this is a "shallow" copy as it copies the object's attributes
247
+ # only, not its associations. The extent of a "deep" copy is application
248
+ # specific and is therefore left to the application to implement according
249
+ # to its need.
250
+ # The dup method does not preserve the timestamps (created|updated)_(at|on).
251
+
252
+ ##
253
+ def initialize_dup(other) # :nodoc:
254
+ cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
255
+ self.class.initialize_attributes(cloned_attributes, :serialized => false)
256
+
257
+ @attributes = cloned_attributes
258
+ @attributes[self.class.primary_key] = nil
259
+
260
+ run_callbacks(:initialize) unless _initialize_callbacks.empty?
261
+
262
+ @changed_attributes = {}
263
+ self.class.column_defaults.each do |attr, orig_value|
264
+ @changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value, @attributes[attr])
265
+ end
266
+
267
+ @aggregation_cache = {}
268
+ @association_cache = {}
269
+ @attributes_cache = {}
270
+
271
+ @new_record = true
272
+
273
+ ensure_proper_type
274
+ super
275
+ end
276
+
277
+ # Populate +coder+ with attributes about this record that should be
278
+ # serialized. The structure of +coder+ defined in this method is
279
+ # guaranteed to match the structure of +coder+ passed to the +init_with+
280
+ # method.
281
+ #
282
+ # Example:
283
+ #
284
+ # class Post < ActiveRecord::Base
285
+ # end
286
+ # coder = {}
287
+ # Post.new.encode_with(coder)
288
+ # coder # => {"attributes" => {"id" => nil, ... }}
289
+ def encode_with(coder)
290
+ coder['attributes'] = attributes
291
+ end
292
+
293
+ # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
294
+ # is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
295
+ #
296
+ # Note that new records are different from any other record by definition, unless the
297
+ # other record is the receiver itself. Besides, if you fetch existing records with
298
+ # +select+ and leave the ID out, you're on your own, this predicate will return false.
299
+ #
300
+ # Note also that destroying a record preserves its ID in the model instance, so deleted
301
+ # models are still comparable.
302
+ def ==(comparison_object)
303
+ super ||
304
+ comparison_object.instance_of?(self.class) &&
305
+ id.present? &&
306
+ comparison_object.id == id
307
+ end
308
+ alias :eql? :==
309
+
310
+ # Delegates to id in order to allow two records of the same type and id to work with something like:
311
+ # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
312
+ def hash
313
+ id.hash
314
+ end
315
+
316
+ # Freeze the attributes hash such that associations are still accessible, even on destroyed records.
317
+ def freeze
318
+ @attributes.freeze
319
+ self
320
+ end
321
+
322
+ # Returns +true+ if the attributes hash has been frozen.
323
+ def frozen?
324
+ @attributes.frozen?
325
+ end
326
+
327
+ # Allows sort on objects
328
+ def <=>(other_object)
329
+ if other_object.is_a?(self.class)
330
+ self.to_key <=> other_object.to_key
331
+ end
332
+ end
333
+
334
+ # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
335
+ # attributes will be marked as read only since they cannot be saved.
336
+ def readonly?
337
+ @readonly
338
+ end
339
+
340
+ # Marks this record as read only.
341
+ def readonly!
342
+ @readonly = true
343
+ end
344
+
345
+ # Returns the connection currently associated with the class. This can
346
+ # also be used to "borrow" the connection to do database work that isn't
347
+ # easily done without going straight to SQL.
348
+ def connection
349
+ ActiveSupport::Deprecation.warn("#connection is deprecated in favour of accessing it via the class")
350
+ self.class.connection
351
+ end
352
+
353
+ # Returns the contents of the record as a nicely formatted string.
354
+ def inspect
355
+ inspection = if @attributes
356
+ self.class.column_names.collect { |name|
357
+ if has_attribute?(name)
358
+ "#{name}: #{attribute_for_inspect(name)}"
359
+ end
360
+ }.compact.join(", ")
361
+ else
362
+ "not initialized"
363
+ end
364
+ "#<#{self.class} #{inspection}>"
365
+ end
366
+
367
+ # Returns a hash of the given methods with their names as keys and returned values as values.
368
+ def slice(*methods)
369
+ Hash[methods.map { |method| [method, public_send(method)] }].with_indifferent_access
370
+ end
371
+
372
+ def set_transaction_state(state) # :nodoc:
373
+ @transaction_state = state
374
+ end
375
+
376
+ def has_transactional_callbacks? # :nodoc:
377
+ !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_create_callbacks.empty?
378
+ end
379
+
380
+ private
381
+
382
+ # Updates the attributes on this particular ActiveRecord object so that
383
+ # if it is associated with a transaction, then the state of the AR object
384
+ # will be updated to reflect the current state of the transaction
385
+ #
386
+ # The @transaction_state variable stores the states of the associated
387
+ # transaction. This relies on the fact that a transaction can only be in
388
+ # one rollback or commit (otherwise a list of states would be required)
389
+ # Each AR object inside of a transaction carries that transaction's
390
+ # TransactionState.
391
+ #
392
+ # This method checks to see if the ActiveRecord object's state reflects
393
+ # the TransactionState, and rolls back or commits the ActiveRecord object
394
+ # as appropriate.
395
+ #
396
+ # Since ActiveRecord objects can be inside multiple transactions, this
397
+ # method recursively goes through the parent of the TransactionState and
398
+ # checks if the ActiveRecord object reflects the state of the object.
399
+ def sync_with_transaction_state
400
+ update_attributes_from_transaction_state(@transaction_state, 0)
401
+ end
402
+
403
+ def update_attributes_from_transaction_state(transaction_state, depth)
404
+ if transaction_state && !has_transactional_callbacks?
405
+ unless @reflects_state[depth]
406
+ if transaction_state.committed?
407
+ committed!
408
+ elsif transaction_state.rolledback?
409
+ rolledback!
410
+ end
411
+ @reflects_state[depth] = true
412
+ end
413
+
414
+ if transaction_state.parent && !@reflects_state[depth+1]
415
+ update_attributes_from_transaction_state(transaction_state.parent, depth+1)
416
+ end
417
+ end
418
+ end
419
+
420
+ # Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
421
+ # of the array, and then rescues from the possible NoMethodError. If those elements are
422
+ # ActiveRecord::Base's, then this triggers the various method_missing's that we have,
423
+ # which significantly impacts upon performance.
424
+ #
425
+ # So we can avoid the method_missing hit by explicitly defining #to_ary as nil here.
426
+ #
427
+ # See also http://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
428
+ def to_ary # :nodoc:
429
+ nil
430
+ end
431
+
432
+ def init_internals
433
+ pk = self.class.primary_key
434
+ @attributes[pk] = nil unless @attributes.key?(pk)
435
+
436
+ @aggregation_cache = {}
437
+ @association_cache = {}
438
+ @attributes_cache = {}
439
+ @previously_changed = {}
440
+ @changed_attributes = {}
441
+ @readonly = false
442
+ @destroyed = false
443
+ @marked_for_destruction = false
444
+ @destroyed_by_association = nil
445
+ @new_record = true
446
+ @txn = nil
447
+ @_start_transaction_state = {}
448
+ @transaction_state = nil
449
+ @reflects_state = [false]
450
+ end
451
+ end
452
+ end