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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +326 -3
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +18 -0
- data/lib/active_record/associations/association.rb +11 -3
- data/lib/active_record/associations/builder/belongs_to.rb +4 -2
- data/lib/active_record/associations/collection_association.rb +8 -8
- data/lib/active_record/associations/collection_proxy.rb +2 -4
- data/lib/active_record/associations/has_many_association.rb +2 -2
- data/lib/active_record/associations/has_one_association.rb +3 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +2 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +14 -1
- data/lib/active_record/associations/preloader.rb +3 -2
- data/lib/active_record/attribute_methods/read.rb +15 -9
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +2 -0
- data/lib/active_record/attribute_methods.rb +26 -2
- data/lib/active_record/autosave_association.rb +8 -8
- data/lib/active_record/callbacks.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +7 -7
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +12 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +16 -2
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +3 -1
- data/lib/active_record/connection_adapters/column.rb +12 -11
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -3
- data/lib/active_record/connection_adapters/mysql_adapter.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/cast.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +7 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +19 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +8 -5
- data/lib/active_record/core.rb +18 -18
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/fixtures.rb +2 -2
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +4 -1
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/model_schema.rb +27 -17
- data/lib/active_record/null_relation.rb +1 -5
- data/lib/active_record/persistence.rb +16 -5
- data/lib/active_record/railtie.rb +1 -0
- data/lib/active_record/railties/databases.rake +4 -1
- data/lib/active_record/reflection.rb +1 -1
- data/lib/active_record/relation/batches.rb +2 -2
- data/lib/active_record/relation/calculations.rb +1 -0
- data/lib/active_record/relation/finder_methods.rb +10 -10
- data/lib/active_record/relation/merger.rb +31 -28
- data/lib/active_record/relation/query_methods.rb +20 -11
- data/lib/active_record/relation.rb +1 -1
- data/lib/active_record/result.rb +15 -1
- data/lib/active_record/sanitization.rb +13 -3
- data/lib/active_record/schema_dumper.rb +5 -1
- data/lib/active_record/tasks/database_tasks.rb +2 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +1 -1
- data/lib/active_record/transactions.rb +5 -5
- data/lib/active_record/validations/uniqueness.rb +2 -2
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +1 -0
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c7b681afcb7c78e77f49102c88638d86f8da054
|
4
|
+
data.tar.gz: ea168d9889ba754dd4569410d613b6ea79c04b57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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/
|
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
|
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
|
-
|
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 =
|
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
|
-
|
86
|
-
raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if
|
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 !=
|
92
|
-
scope.raise_record_not_found_exception!(
|
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.
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
37
|
-
#
|
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 = @
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
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)
|