activerecord 4.0.0 → 4.0.1

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +326 -3
  3. data/README.rdoc +1 -1
  4. data/lib/active_record/association_relation.rb +18 -0
  5. data/lib/active_record/associations/association.rb +11 -3
  6. data/lib/active_record/associations/builder/belongs_to.rb +4 -2
  7. data/lib/active_record/associations/collection_association.rb +8 -8
  8. data/lib/active_record/associations/collection_proxy.rb +2 -4
  9. data/lib/active_record/associations/has_many_association.rb +2 -2
  10. data/lib/active_record/associations/has_one_association.rb +3 -1
  11. data/lib/active_record/associations/join_dependency/join_association.rb +2 -0
  12. data/lib/active_record/associations/join_dependency/join_part.rb +14 -1
  13. data/lib/active_record/associations/preloader.rb +3 -2
  14. data/lib/active_record/attribute_methods/read.rb +15 -9
  15. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  16. data/lib/active_record/attribute_methods/write.rb +2 -0
  17. data/lib/active_record/attribute_methods.rb +26 -2
  18. data/lib/active_record/autosave_association.rb +8 -8
  19. data/lib/active_record/callbacks.rb +4 -1
  20. data/lib/active_record/connection_adapters/abstract/database_statements.rb +7 -7
  21. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +12 -3
  22. data/lib/active_record/connection_adapters/abstract_adapter.rb +16 -2
  23. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +3 -1
  24. data/lib/active_record/connection_adapters/column.rb +12 -11
  25. data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -3
  26. data/lib/active_record/connection_adapters/mysql_adapter.rb +19 -9
  27. data/lib/active_record/connection_adapters/postgresql/cast.rb +1 -1
  28. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +7 -6
  29. data/lib/active_record/connection_adapters/postgresql/oid.rb +5 -0
  30. data/lib/active_record/connection_adapters/postgresql/quoting.rb +2 -0
  31. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +7 -10
  32. data/lib/active_record/connection_adapters/postgresql_adapter.rb +19 -13
  33. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +8 -5
  34. data/lib/active_record/core.rb +18 -18
  35. data/lib/active_record/dynamic_matchers.rb +1 -1
  36. data/lib/active_record/fixtures.rb +2 -2
  37. data/lib/active_record/locking/optimistic.rb +1 -1
  38. data/lib/active_record/migration/command_recorder.rb +4 -1
  39. data/lib/active_record/migration.rb +1 -1
  40. data/lib/active_record/model_schema.rb +27 -17
  41. data/lib/active_record/null_relation.rb +1 -5
  42. data/lib/active_record/persistence.rb +16 -5
  43. data/lib/active_record/railtie.rb +1 -0
  44. data/lib/active_record/railties/databases.rake +4 -1
  45. data/lib/active_record/reflection.rb +1 -1
  46. data/lib/active_record/relation/batches.rb +2 -2
  47. data/lib/active_record/relation/calculations.rb +1 -0
  48. data/lib/active_record/relation/finder_methods.rb +10 -10
  49. data/lib/active_record/relation/merger.rb +31 -28
  50. data/lib/active_record/relation/query_methods.rb +20 -11
  51. data/lib/active_record/relation.rb +1 -1
  52. data/lib/active_record/result.rb +15 -1
  53. data/lib/active_record/sanitization.rb +13 -3
  54. data/lib/active_record/schema_dumper.rb +5 -1
  55. data/lib/active_record/tasks/database_tasks.rb +2 -1
  56. data/lib/active_record/tasks/sqlite_database_tasks.rb +1 -1
  57. data/lib/active_record/transactions.rb +5 -5
  58. data/lib/active_record/validations/uniqueness.rb +2 -2
  59. data/lib/active_record/version.rb +1 -1
  60. data/lib/active_record.rb +1 -0
  61. metadata +8 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 76ddb57b66b29722a983d38eba75ebc3e94610ea
4
- data.tar.gz: 743a630e5e1722c2655ca8c167dbb5be2ab49afb
3
+ metadata.gz: 5c7b681afcb7c78e77f49102c88638d86f8da054
4
+ data.tar.gz: ea168d9889ba754dd4569410d613b6ea79c04b57
5
5
  SHA512:
6
- metadata.gz: a643a5988de90b3145ab259ecc0f20acba5e66db188ad8ebfbdd12e14352e26d696faf570cc04c2da30e70bc1a490d9107cb4086f59b90614088941c96f095e3
7
- data.tar.gz: 513f56748c0e72bc073a068f29846737aeb95c11fd3fc23672295027a6d475c2764613f3b1653cdb8d32ac61b4dfcff32cade6279fad13ad4030bd1e01e536b0
6
+ metadata.gz: 08a6d5f0dbe0186a931fe72a9f1ff7d5380b211ad11fc1a2037adf9abf3fb34b5af8df245b9569db37bcbe86b3c1dd17a444681c2cb9ac97c5b9a21ef088348a
7
+ data.tar.gz: fb894bd5fa52bf9bb37de1eeb90aacf59587e61f55577c478a0b665758a1d6b0328f9400f9fcd9c170abf2e005151a8d6ec30d5e9a08c056920308278fbf990a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,328 @@
1
+ ## Rails 4.0.1 (November 01, 2013) ##
2
+
3
+ * `NullRelation#pluck` takes a list of columns
4
+
5
+ The method signature in `NullRelation` was updated to mimic that in
6
+ `Calculations`.
7
+
8
+ *Derek Prior*
9
+
10
+ * `scope_chain` should not be mutated for other reflections.
11
+
12
+ Currently `scope_chain` uses same array for building different
13
+ `scope_chain` for different associations. During processing
14
+ these arrays are sometimes mutated and because of in-place
15
+ mutation the changed `scope_chain` impacts other reflections.
16
+
17
+ Fix is to dup the value before adding to the `scope_chain`.
18
+
19
+ Fixes #3882.
20
+
21
+ *Neeraj Singh*
22
+
23
+ * Prevent the inversed association from being reloaded on save.
24
+
25
+ Fixes #9499.
26
+
27
+ *Dmitry Polushkin*
28
+
29
+ * `Relation#order` quotes the column name if you pass a `Symbol`.
30
+ Fixes #11870.
31
+
32
+ Example:
33
+
34
+ # Before
35
+ Post.order(:id).to_sql == '... ORDER BY "posts".id ASC'
36
+
37
+ # After
38
+ Post.order(:id).to_sql == '... ORDER BY "posts"."id" ASC'
39
+
40
+ *Yves Senn*
41
+
42
+ * Generate subquery for `Relation` if it passed as array condition for `where`
43
+ method.
44
+
45
+ Example:
46
+
47
+ # Before
48
+ Blog.where('id in (?)', Blog.where(id: 1))
49
+ # => SELECT "blogs".* FROM "blogs" WHERE "blogs"."id" = 1
50
+ # => SELECT "blogs".* FROM "blogs" WHERE (id IN (1))
51
+
52
+ # After
53
+ Blog.where('id in (?)', Blog.where(id: 1).select(:id))
54
+ # => SELECT "blogs".* FROM "blogs"
55
+ # WHERE "blogs"."id" IN (SELECT "blogs"."id" FROM "blogs" WHERE "blogs"."id" = 1)
56
+
57
+ Fixes #12415.
58
+
59
+ *Paul Nikitochkin*
60
+
61
+ * For missed association exception message
62
+ which is raised in `ActiveRecord::Associations::Preloader` class
63
+ added owner record class name in order to simplify to find problem code.
64
+
65
+ *Paul Nikitochkin*
66
+
67
+ * Fixes bug when using includes combined with select, the select statement was overwritten.
68
+
69
+ Fixes #11773.
70
+
71
+ *Edo Balvers*
72
+
73
+ * Objects instantiated using a null relationship will now retain the
74
+ attributes of the where clause.
75
+
76
+ Fixes #11676, #11675, #11376.
77
+
78
+ *Paul Nikitochkin*, *Peter Brown*, *Nthalk*
79
+
80
+ * Fixed `ActiveRecord::Associations::CollectionAssociation#find`
81
+ when using `has_many` association with `:inverse_of` and finding an array of one element,
82
+ it should return an array of one element too.
83
+
84
+ *arthurnn*
85
+
86
+ * Callbacks on has_many should access the in memory parent if a inverse_of is set.
87
+
88
+ *arthurnn*
89
+
90
+ * Migration dump UUID default functions to schema.rb.
91
+
92
+ Fixes #10751.
93
+
94
+ *kennyj*
95
+
96
+ * Fixed a bug in `ActiveRecord::Associations::CollectionAssociation#find_by_scan`
97
+ when using `has_many` association with `:inverse_of` option and UUID primary key.
98
+
99
+ Fixes #10450.
100
+
101
+ *kennyj*
102
+
103
+ * Fix: joins association, with defined in the scope block constraints by using several
104
+ where constraints and at least of them is not `Arel::Nodes::Equality`,
105
+ generates invalid SQL expression.
106
+
107
+ Fixes: #11963
108
+
109
+ *Paul Nikitochkin*
110
+
111
+ * Make possible to run SQLite rake tasks without the `Rails` constant defined.
112
+
113
+ *Damien Mathieu*
114
+
115
+ * Allow Relation#from to accept other relations with bind values.
116
+
117
+ *Ryan Wallace*
118
+
119
+ * Make `find_in_batches` and `find_each` work without a logger.
120
+
121
+ *Dmitry Polushkin*
122
+
123
+ * Fix inserts with prepared statements disabled.
124
+
125
+ Fixes #12023.
126
+
127
+ *Rafael Mendonça França*
128
+
129
+ * Setting a has_one association on a new record no longer causes an empty
130
+ transaction.
131
+
132
+ *Dylan Thacker-Smith*
133
+
134
+ * Fix `AR::Relation#merge` sometimes failing to preserve `readonly(false)` flag.
135
+
136
+ *thedarkone*
137
+
138
+ * PostgreSQL adapter recognizes negative money values formatted with
139
+ parentheses (eg. `($1.25) # => -1.25`)).
140
+ Fixes #11899.
141
+
142
+ * Yves Senn*
143
+
144
+ * Do not load all child records for inverse case.
145
+
146
+ currently `post.comments.find(Comment.first.id)` would load all
147
+ comments for the given post to set the inverse association.
148
+
149
+ This has a huge performance penalty. Because if post has 100k
150
+ records and all these 100k records would be loaded in memory
151
+ even though the comment id was supplied.
152
+
153
+ Fix is to use in-memory records only if loaded? is true. Otherwise
154
+ load the records using full sql.
155
+
156
+ Fixes #10509.
157
+
158
+ *Neeraj Singh*
159
+
160
+ * `ActiveRecord::FinderMethods#exists?` returns `true`/`false` in all cases.
161
+
162
+ *Xavier Noria*
163
+
164
+ * Load fixtures from linked folders.
165
+
166
+ *Kassio Borges*
167
+
168
+ * Create a directory for sqlite3 file if not present on the system.
169
+
170
+ *Richard Schneeman*
171
+
172
+ * Removed redundant override of `xml` column definition for PG,
173
+ in order to use `xml` column type instead of `text`.
174
+
175
+ *Paul Nikitochkin*, *Michael Nikitochkin*
176
+
177
+ * Revert `ActiveRecord::Relation#order` change that make new order
178
+ prepend the old one.
179
+
180
+ Before:
181
+
182
+ User.order("name asc").order("created_at desc")
183
+ # SELECT * FROM users ORDER BY created_at desc, name asc
184
+
185
+ After:
186
+
187
+ User.order("name asc").order("created_at desc")
188
+ # SELECT * FROM users ORDER BY name asc, created_at desc
189
+
190
+ This also affects order defined in `default_scope` or any kind of associations.
191
+
192
+ *Rafael Mendonça França*
193
+
194
+ * When using optimistic locking, `update` was not passing the column to `quote_value`
195
+ to allow the connection adapter to properly determine how to quote the value. This was
196
+ affecting certain databases that use specific column types.
197
+
198
+ Fixes #6763.
199
+
200
+ *Alfred Wong*
201
+
202
+ * `change_column` for PostgreSQL adapter respects the `:array` option.
203
+
204
+ *Yves Senn*
205
+
206
+ * Fixes bug introduced by #3329. Now, when autosaving associations,
207
+ deletions happen before inserts and saves. This prevents a
208
+ 'duplicate unique value' database error that would occur if a record being created had
209
+ the same value on a unique indexed field as that of a record being destroyed.
210
+
211
+ *Johnny Holton*
212
+
213
+ * Flatten merged join values before building the joins.
214
+
215
+ While joining values special treatment is given to string values.
216
+ By flattening the array it ensures that string values are detected
217
+ as strings and not arrays.
218
+
219
+ Fixes #10669.
220
+
221
+ *Neeraj Singh and iwiznia*
222
+
223
+ * Remove extra select and update queries on `save`/`touch`/`destroy` Active Record model
224
+ with belongs to reflection with option `touch: true`.
225
+
226
+ Fixes #11288.
227
+
228
+ *Paul Nikitochkin*
229
+
230
+ * Support array as root element in JSON fields.
231
+
232
+ *Alexey Noskov & Francesco Rodriguez*
233
+
234
+ * Apply default scope when joining associations. For example:
235
+
236
+ class Post < ActiveRecord::Base
237
+ default_scope -> { where published: true }
238
+ end
239
+
240
+ class Comment
241
+ belongs_to :post
242
+ end
243
+
244
+ When calling `Comment.joins(:post)`, we expect to receive only
245
+ comments on published posts, since that is the default scope for
246
+ posts.
247
+
248
+ Before this change, the default scope from `Post` was not applied,
249
+ so we'd get comments on unpublished posts.
250
+
251
+ *Jon Leighton*
252
+
253
+ * `inspect` on Active Record model classes does not initiate a
254
+ new connection. This means that calling `inspect`, when the
255
+ database is missing, will no longer raise an exception.
256
+
257
+ Fixes #10936.
258
+
259
+ Example:
260
+
261
+ Author.inspect # => "Author(no database connection)"
262
+
263
+ *Yves Senn*
264
+
265
+ * Fix mysql2 adapter raises the correct exception when executing a query on a
266
+ closed connection.
267
+
268
+ *Yves Senn*
269
+
270
+ * Fix the `:primary_key` option for `has_many` associations.
271
+
272
+ Fixes #10693.
273
+
274
+ *Yves Senn*
275
+
276
+ * Fix bug where tiny types are incorectly coerced as booleand when the length is more than 1.
277
+
278
+ Fixes #10620.
279
+
280
+ *Aaron Patterson*
281
+
282
+ * Also support extensions in PostgreSQL 9.1. This feature has been supported since 9.1.
283
+
284
+ *kennyj*
285
+
286
+ * Deprecate `ConnectionAdapters::SchemaStatements#distinct`,
287
+ as it is no longer used by internals.
288
+
289
+ *Ben Woosley#
290
+
291
+ * Remove not needed bind variables. Port of commit #5082345.
292
+
293
+ Fixes #10958.
294
+
295
+ *Neeraj Singh*
296
+
297
+ * Confirm a record has not already been destroyed before decrementing counter cache.
298
+
299
+ *Ben Tucker*
300
+
301
+ * Fixed a bug in `ActiveRecord#sanitize_sql_hash_for_conditions` in which
302
+ `self.class` is an argument to `PredicateBuilder#build_from_hash`
303
+ causing `PredicateBuilder` to call non-existent method
304
+ `Class#reflect_on_association`.
305
+
306
+ *Zach Ohlgren*
307
+
308
+ * While removing index if column option is missing then raise IrreversibleMigration exception.
309
+
310
+ Following code should raise `IrreversibleMigration`. But the code was
311
+ failing since options is an array and not a hash.
312
+
313
+ def change
314
+ change_table :users do |t|
315
+ t.remove_index [:name, :email]
316
+ end
317
+ end
318
+
319
+ Fix was to check if the options is a Hash before operating on it.
320
+
321
+ Fixes #10419.
322
+
323
+ *Neeraj Singh*
324
+
325
+
1
326
  ## Rails 4.0.0 (June 25, 2013) ##
2
327
 
3
328
  * Fix `add_column` with `array` option when using PostgreSQL. Fixes #10432
@@ -30,7 +355,6 @@
30
355
 
31
356
  *Adam Anderson*
32
357
 
33
-
34
358
  * Fix pending migrations error when loading schema and `ActiveRecord::Base.table_name_prefix`
35
359
  is not blank.
36
360
 
@@ -2046,7 +2370,7 @@
2046
2370
  * The primary key is always initialized in the @attributes hash to `nil` (unless
2047
2371
  another value has been specified).
2048
2372
 
2049
- *Aaron Paterson*
2373
+ *Aaron Patterson*
2050
2374
 
2051
2375
  * In previous releases, the following would generate a single query with
2052
2376
  an `OUTER JOIN comments`, rather than two separate queries:
@@ -2098,5 +2422,4 @@
2098
2422
 
2099
2423
  *Aaron Patterson*
2100
2424
 
2101
-
2102
2425
  Please check [3-2-stable](https://github.com/rails/rails/blob/3-2-stable/activerecord/CHANGELOG.md) for previous changes.
data/README.rdoc CHANGED
@@ -192,7 +192,7 @@ The latest version of Active Record can be installed with RubyGems:
192
192
 
193
193
  Source code can be downloaded as part of the Rails project on GitHub:
194
194
 
195
- * https://github.com/rails/rails/tree/master/activerecord
195
+ * https://github.com/rails/rails/tree/4-0-stable/activerecord
196
196
 
197
197
 
198
198
  == License
@@ -0,0 +1,18 @@
1
+ module ActiveRecord
2
+ class AssociationRelation < Relation
3
+ def initialize(klass, table, association)
4
+ super(klass, table)
5
+ @association = association
6
+ end
7
+
8
+ def proxy_association
9
+ @association
10
+ end
11
+
12
+ private
13
+
14
+ def exec_queries
15
+ super.each { |r| @association.set_inverse_instance r }
16
+ end
17
+ end
18
+ end
@@ -18,6 +18,7 @@ module ActiveRecord
18
18
  # HasManyThroughAssociation + ThroughAssociation
19
19
  class Association #:nodoc:
20
20
  attr_reader :owner, :target, :reflection
21
+ attr_accessor :inversed
21
22
 
22
23
  delegate :options, :to => :reflection
23
24
 
@@ -43,6 +44,7 @@ module ActiveRecord
43
44
  @loaded = false
44
45
  @target = nil
45
46
  @stale_state = nil
47
+ @inversed = false
46
48
  end
47
49
 
48
50
  # Reloads the \target and returns +self+ on success.
@@ -60,8 +62,9 @@ module ActiveRecord
60
62
 
61
63
  # Asserts the \target has been loaded setting the \loaded flag to +true+.
62
64
  def loaded!
63
- @loaded = true
65
+ @loaded = true
64
66
  @stale_state = stale_state
67
+ @inversed = false
65
68
  end
66
69
 
67
70
  # The target is stale if the target no longer points to the record(s) that the
@@ -71,7 +74,7 @@ module ActiveRecord
71
74
  #
72
75
  # Note that if the target has not been loaded, it is not considered stale.
73
76
  def stale_target?
74
- loaded? && @stale_state != stale_state
77
+ !inversed && loaded? && @stale_state != stale_state
75
78
  end
76
79
 
77
80
  # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
@@ -110,6 +113,7 @@ module ActiveRecord
110
113
  if record && invertible_for?(record)
111
114
  inverse = record.association(inverse_reflection_for(record).name)
112
115
  inverse.target = owner
116
+ inverse.inversed = true
113
117
  end
114
118
  end
115
119
 
@@ -122,7 +126,11 @@ module ActiveRecord
122
126
  # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
123
127
  # through association's scope)
124
128
  def target_scope
125
- klass.all
129
+ all = klass.all
130
+ scope = AssociationRelation.new(klass, klass.arel_table, self)
131
+ scope.merge! all
132
+ scope.default_scoped = all.default_scoped?
133
+ scope
126
134
  end
127
135
 
128
136
  # Loads the \target if needed and returns it.
@@ -34,7 +34,9 @@ module ActiveRecord::Associations::Builder
34
34
  def belongs_to_counter_cache_before_destroy_for_#{name}
35
35
  unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == #{foreign_key.to_sym.inspect}
36
36
  record = #{name}
37
- record.class.decrement_counter(:#{cache_column}, record.id) unless record.nil?
37
+ if record && !self.destroyed?
38
+ record.class.decrement_counter(:#{cache_column}, record.id)
39
+ end
38
40
  end
39
41
  end
40
42
 
@@ -68,7 +70,7 @@ module ActiveRecord::Associations::Builder
68
70
  mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
69
71
  def belongs_to_touch_after_save_or_destroy_for_#{name}
70
72
  foreign_key_field = #{reflection.foreign_key.inspect}
71
- old_foreign_id = attribute_was(foreign_key_field)
73
+ old_foreign_id = changed_attributes[foreign_key_field]
72
74
 
73
75
  if old_foreign_id
74
76
  klass = association(#{name.inspect}).klass
@@ -81,15 +81,15 @@ module ActiveRecord
81
81
  else
82
82
  if options[:finder_sql]
83
83
  find_by_scan(*args)
84
- elsif options[:inverse_of]
85
- args = args.flatten
86
- raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if args.blank?
84
+ elsif options[:inverse_of] && loaded?
85
+ args_flatten = args.flatten
86
+ raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if args_flatten.blank?
87
87
 
88
88
  result = find_by_scan(*args)
89
89
 
90
90
  result_size = Array(result).size
91
- if !result || result_size != args.size
92
- scope.raise_record_not_found_exception!(args, result_size, args.size)
91
+ if !result || result_size != args_flatten.size
92
+ scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
93
93
  else
94
94
  result
95
95
  end
@@ -583,14 +583,14 @@ module ActiveRecord
583
583
  # specified, then #find scans the entire collection.
584
584
  def find_by_scan(*args)
585
585
  expects_array = args.first.kind_of?(Array)
586
- ids = args.flatten.compact.map{ |arg| arg.to_i }.uniq
586
+ ids = args.flatten.compact.map{ |arg| arg.to_s }.uniq
587
587
 
588
588
  if ids.size == 1
589
589
  id = ids.first
590
- record = load_target.detect { |r| id == r.id }
590
+ record = load_target.detect { |r| id == r.id.to_s }
591
591
  expects_array ? [ record ] : record
592
592
  else
593
- load_target.select { |r| ids.include?(r.id) }
593
+ load_target.select { |r| ids.include?(r.id.to_s) }
594
594
  end
595
595
  end
596
596
 
@@ -830,7 +830,7 @@ module ActiveRecord
830
830
  # person.pets.include?(Pet.find(20)) # => true
831
831
  # person.pets.include?(Pet.find(21)) # => false
832
832
  def include?(record)
833
- @association.include?(record)
833
+ !!@association.include?(record)
834
834
  end
835
835
 
836
836
  def proxy_association
@@ -847,9 +847,7 @@ module ActiveRecord
847
847
 
848
848
  # Returns a <tt>Relation</tt> object for the records in this association
849
849
  def scope
850
- @association.scope.tap do |scope|
851
- scope.proxy_association = @association
852
- end
850
+ @association.scope
853
851
  end
854
852
 
855
853
  # :nodoc:
@@ -32,6 +32,7 @@ module ActiveRecord
32
32
 
33
33
  def insert_record(record, validate = true, raise = false)
34
34
  set_owner_attributes(record)
35
+ set_inverse_instance(record)
35
36
 
36
37
  if raise
37
38
  record.save!(:validate => validate)
@@ -115,8 +116,7 @@ module ActiveRecord
115
116
  if records == :all
116
117
  scope = self.scope
117
118
  else
118
- keys = records.map { |r| r[reflection.association_primary_key] }
119
- scope = self.scope.where(reflection.association_primary_key => keys)
119
+ scope = self.scope.where(reflection.klass.primary_key => records)
120
120
  end
121
121
 
122
122
  if method == :delete_all
@@ -27,6 +27,8 @@ module ActiveRecord
27
27
 
28
28
  return self.target if !(target || record)
29
29
  if (target != record) || record.changed?
30
+ save &&= owner.persisted?
31
+
30
32
  transaction_if(save) do
31
33
  remove_target!(options[:dependent]) if target && !target.destroyed?
32
34
 
@@ -34,7 +36,7 @@ module ActiveRecord
34
36
  set_owner_attributes(record)
35
37
  set_inverse_instance(record)
36
38
 
37
- if owner.persisted? && save && !record.save
39
+ if save && !record.save
38
40
  nullify_owner_attributes(record)
39
41
  set_owner_attributes(target) if target
40
42
  raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
@@ -106,6 +106,8 @@ module ActiveRecord
106
106
  ]
107
107
  end
108
108
 
109
+ scope_chain_items += [reflection.klass.send(:build_default_scope)].compact
110
+
109
111
  scope_chain_items.each do |item|
110
112
  unless item.is_a?(Relation)
111
113
  item = ActiveRecord::Relation.new(reflection.klass, table).instance_exec(self, &item)
@@ -62,7 +62,20 @@ module ActiveRecord
62
62
  end
63
63
 
64
64
  def extract_record(row)
65
- Hash[column_names_with_alias.map{|cn, an| [cn, row[an]]}]
65
+ # This code is performance critical as it is called per row.
66
+ # see: https://github.com/rails/rails/pull/12185
67
+ hash = {}
68
+
69
+ index = 0
70
+ length = column_names_with_alias.length
71
+
72
+ while index < length
73
+ column_name, alias_name = column_names_with_alias[index]
74
+ hash[column_name] = row[alias_name]
75
+ index += 1
76
+ end
77
+
78
+ hash
66
79
  end
67
80
 
68
81
  def record_id(row)
@@ -141,10 +141,11 @@ module ActiveRecord
141
141
 
142
142
  def records_by_reflection(association)
143
143
  records.group_by do |record|
144
- reflection = record.class.reflections[association]
144
+ record_class = record.class
145
+ reflection = record_class.reflections[association]
145
146
 
146
147
  unless reflection
147
- raise ActiveRecord::ConfigurationError, "Association named '#{association}' was not found; " \
148
+ raise ActiveRecord::ConfigurationError, "Association named '#{association}' was not found on #{record_class.name}; " \
148
149
  "perhaps you misspelled it?"
149
150
  end
150
151
 
@@ -33,8 +33,11 @@ module ActiveRecord
33
33
  protected
34
34
 
35
35
  # We want to generate the methods via module_eval rather than
36
- # define_method, because define_method is slower on dispatch and
37
- # uses more memory (because it creates a closure).
36
+ # define_method, because define_method is slower on dispatch.
37
+ # Evaluating many similar methods may use more memory as the instruction
38
+ # sequences are duplicated and cached (in MRI). define_method may
39
+ # be slower on dispatch, but if you're careful about the closure
40
+ # created, then define_method will consume much less memory.
38
41
  #
39
42
  # But sometimes the database might return columns with
40
43
  # characters that are not allowed in normal method names (like
@@ -49,6 +52,8 @@ module ActiveRecord
49
52
  # key the @attributes_cache in read_attribute.
50
53
  def define_method_attribute(name)
51
54
  safe_name = name.unpack('h*').first
55
+ generated_attribute_methods::AttrNames.set_name_cache safe_name, name
56
+
52
57
  generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
53
58
  def __temp__#{safe_name}
54
59
  read_attribute(AttrNames::ATTR_#{safe_name}) { |n| missing_attribute(n, caller) }
@@ -77,13 +82,14 @@ module ActiveRecord
77
82
  # We use #[] first as a perf optimization for non-nil values. See https://gist.github.com/jonleighton/3552829.
78
83
  name = attr_name.to_s
79
84
  @attributes_cache[name] || @attributes_cache.fetch(name) {
80
- column = @columns_hash.fetch(name) {
81
- return @attributes.fetch(name) {
82
- if name == 'id' && self.class.primary_key != name
83
- read_attribute(self.class.primary_key)
84
- end
85
- }
86
- }
85
+ column = @column_types_override[name] if @column_types_override
86
+ column ||= @column_types[name]
87
+
88
+ return @attributes.fetch(name) {
89
+ if name == 'id' && self.class.primary_key != name
90
+ read_attribute(self.class.primary_key)
91
+ end
92
+ } unless column
87
93
 
88
94
  value = @attributes.fetch(name) {
89
95
  return block_given? ? yield(name) : nil
@@ -51,7 +51,7 @@ module ActiveRecord
51
51
  def create_time_zone_conversion_attribute?(name, column)
52
52
  time_zone_aware_attributes &&
53
53
  !self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) &&
54
- [:datetime, :timestamp].include?(column.type)
54
+ (:datetime == column.type || :timestamp == column.type)
55
55
  end
56
56
  end
57
57
  end
@@ -14,6 +14,8 @@ module ActiveRecord
14
14
  # this code.
15
15
  def define_method_attribute=(name)
16
16
  safe_name = name.unpack('h*').first
17
+ generated_attribute_methods::AttrNames.set_name_cache safe_name, name
18
+
17
19
  generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
18
20
  def __temp__#{safe_name}=(value)
19
21
  write_attribute(AttrNames::ATTR_#{safe_name}, value)