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.
- data/CHANGELOG.md +148 -2
- data/lib/active_record/associations/association.rb +9 -3
- data/lib/active_record/associations/belongs_to_association.rb +1 -1
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +2 -1
- data/lib/active_record/associations/builder/belongs_to.rb +4 -1
- data/lib/active_record/associations/builder/belongs_to.rb.orig +95 -0
- data/lib/active_record/associations/collection_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +1 -2
- data/lib/active_record/associations/has_many_association.rb.orig +116 -0
- data/lib/active_record/associations/join_dependency.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +6 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/autosave_association.rb +7 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb.orig +619 -0
- data/lib/active_record/connection_adapters/connection_specification.rb.orig +124 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/cast.rb.orig +136 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb.orig +485 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -3
- data/lib/active_record/core.rb.orig +452 -0
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/model_schema.rb +4 -2
- data/lib/active_record/nested_attributes.rb +41 -17
- data/lib/active_record/railtie.rb +6 -7
- data/lib/active_record/railties/databases.rake +2 -1
- data/lib/active_record/relation/calculations.rb +5 -6
- data/lib/active_record/relation/calculations.rb.orig +378 -0
- data/lib/active_record/relation/finder_methods.rb +1 -0
- data/lib/active_record/relation/finder_methods.rb.orig +405 -0
- data/lib/active_record/relation/spawn_methods.rb +34 -3
- data/lib/active_record/store.rb +1 -1
- data/lib/active_record/version.rb +2 -2
- data/lib/rails/generators/active_record/observer/observer_generator.rb.orig +15 -0
- metadata +117 -70
- checksums.yaml +0 -7
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,147 @@
|
|
1
|
-
## Rails 3.2.
|
1
|
+
## Rails 3.2.14.rc1 (Jul 8, 2013) ##
|
2
|
+
|
3
|
+
* Do not shallow the original exception in `exec_cache` on PostgreSQL adapter.
|
4
|
+
|
5
|
+
Fixes #11260.
|
6
|
+
|
7
|
+
*Rafael Mendonça França*
|
8
|
+
|
9
|
+
* Fix `ActiveRecord::Store` incorrectly tracking changes of its attributes.
|
10
|
+
Fixes #10373.
|
11
|
+
|
12
|
+
*Janko Marohnić*
|
13
|
+
|
14
|
+
* Fix a bug that prevented the use of the default STI inheritance column
|
15
|
+
(ActiveRecord::Base.inheritance_column = 'some_column'.)
|
16
|
+
|
17
|
+
*chapmajs + Takehiro Adachi*
|
18
|
+
|
19
|
+
* Fix mysql2 adapter raises the correct exception when executing a query on a
|
20
|
+
closed connection.
|
21
|
+
|
22
|
+
*Yves Senn*
|
23
|
+
|
24
|
+
* Fixes bug where `Company.new.contract_ids` would incorrectly load
|
25
|
+
all non-associated contracts.
|
26
|
+
|
27
|
+
Example:
|
28
|
+
|
29
|
+
company = Company.new # Company has many :contracts
|
30
|
+
|
31
|
+
# before
|
32
|
+
company.contract_ids # => SELECT ... WHERE `contracts`.`company_id` IS NULL
|
33
|
+
|
34
|
+
# after
|
35
|
+
company.contract_ids # => []
|
36
|
+
|
37
|
+
*Jared Armstrong*
|
38
|
+
|
39
|
+
* Fix the `:primary_key` option for `has_many` associations.
|
40
|
+
Fixes #10693.
|
41
|
+
|
42
|
+
*Yves Senn*
|
43
|
+
|
44
|
+
* fixes bug introduced by #3329. Now, when autosaving associations,
|
45
|
+
deletions happen before inserts and saves. This prevents a 'duplicate
|
46
|
+
unique value' database error that would occur if a record being created had
|
47
|
+
the same value on a unique indexed field as that of a record being destroyed.
|
48
|
+
|
49
|
+
Backport of #10417
|
50
|
+
|
51
|
+
*Johnny Holton*
|
52
|
+
|
53
|
+
* Fix that under some conditions, Active Record could produce invalid SQL of the sort:
|
54
|
+
"SELECT DISTINCT DISTINCT".
|
55
|
+
|
56
|
+
Backport of #6792.
|
57
|
+
|
58
|
+
*Ben Woosley*
|
59
|
+
|
60
|
+
* Require `ActiveRecord::Base` in railtie hooks for rake_tasks, console and runner to
|
61
|
+
avoid circular constant loading issues.
|
62
|
+
|
63
|
+
Backport #7695.
|
64
|
+
|
65
|
+
Fixes #7683 and #882
|
66
|
+
|
67
|
+
*Ben Holley*
|
68
|
+
|
69
|
+
* Maintain context for joins within ActiveRecord::Relation merges.
|
70
|
+
Backport #10164.
|
71
|
+
|
72
|
+
*Neeraj Singh + Andrew Horner*
|
73
|
+
|
74
|
+
* Make sure the `EXPLAIN` command is never triggered by a `select_db` call.
|
75
|
+
|
76
|
+
*Daniel Schierbeck*
|
77
|
+
|
78
|
+
* Revert changes on `pluck` that was ignoring the select clause when the relation already
|
79
|
+
has one. This caused a regression since it changed the behavior in a stable release.
|
80
|
+
|
81
|
+
Fixes #9777.
|
82
|
+
|
83
|
+
*Rafael Mendonça França*
|
84
|
+
|
85
|
+
* Confirm a record has not already been destroyed before decrementing counter cache.
|
86
|
+
|
87
|
+
*Ben Tucker*
|
88
|
+
|
89
|
+
* Default values for PostgreSQL bigint types now get parsed and dumped to the
|
90
|
+
schema correctly.
|
91
|
+
Backport #10098.
|
92
|
+
|
93
|
+
*Erik Peterson*
|
94
|
+
|
95
|
+
* Removed warning when `auto_explain_threshold_in_seconds` is set and the
|
96
|
+
connection adapter doesn't support explain.
|
97
|
+
This is causing a regression since the Active Record Railtie is trying to
|
98
|
+
connect to the development database in the application boot.
|
99
|
+
|
100
|
+
*Rafael Mendonça França*
|
101
|
+
|
102
|
+
* Do not reset `inheritance_column` when it's set explicitly.
|
103
|
+
Backport of #5327.
|
104
|
+
|
105
|
+
*kennyj + Fred Wu*
|
106
|
+
|
107
|
+
* Fix a problem wrong exception is occured
|
108
|
+
when raising no translatable exception in PostgreSQL.
|
109
|
+
|
110
|
+
*kennyj*
|
111
|
+
|
112
|
+
* Resets the postgres search path in the structure.sql after the structure
|
113
|
+
is dumped in order to find schema_migrations table when multiples schemas
|
114
|
+
are used.
|
115
|
+
Fixes #9796.
|
116
|
+
|
117
|
+
*Juan M. Cuello + Dembskiy Alexander*
|
118
|
+
|
119
|
+
* Reload the association target if it's stale. `@stale_state` should be nil
|
120
|
+
when a model isn't saved.
|
121
|
+
Fixes #7526.
|
122
|
+
|
123
|
+
*Larry Lv*
|
124
|
+
|
125
|
+
* Don't read CSV files during execution of `db:fixtures:load`. CSV support for
|
126
|
+
fixtures was removed some time ago but the task was still loading them, even
|
127
|
+
though later the code was looking for the related yaml file instead.
|
128
|
+
|
129
|
+
*kennyj*
|
130
|
+
|
131
|
+
|
132
|
+
## Rails 3.2.13 (Mar 18, 2013) ##
|
133
|
+
|
134
|
+
* Chaining multiple preloaded scopes will correctly preload all the scopes
|
135
|
+
at the same time.
|
136
|
+
|
137
|
+
*Chris Geihsler*
|
2
138
|
|
3
139
|
* Reverted 921a296a3390192a71abeec6d9a035cc6d1865c8, 'Quote numeric values
|
4
140
|
compared to string columns.' This caused several regressions.
|
5
141
|
|
6
142
|
*Steve Klabnik*
|
7
143
|
|
8
|
-
* Fix overriding of attributes by default_scope on `ActiveRecord::Base#dup`.
|
144
|
+
* Fix overriding of attributes by `default_scope` on `ActiveRecord::Base#dup`.
|
9
145
|
|
10
146
|
*Hiroshige UMINO*
|
11
147
|
|
@@ -223,6 +359,16 @@
|
|
223
359
|
|
224
360
|
*Victor Costan*
|
225
361
|
|
362
|
+
* `#pluck` can be used on a relation with `select` clause.
|
363
|
+
Fixes #7551.
|
364
|
+
Backport of #8176.
|
365
|
+
|
366
|
+
Example:
|
367
|
+
|
368
|
+
Topic.select([:approved, :id]).order(:id).pluck(:id)
|
369
|
+
|
370
|
+
*Yves Senn*
|
371
|
+
|
226
372
|
* Use `nil?` instead of `blank?` to check whether dynamic finder with a bang
|
227
373
|
should raise RecordNotFound.
|
228
374
|
Fixes #7238.
|
@@ -46,6 +46,7 @@ module ActiveRecord
|
|
46
46
|
@loaded = false
|
47
47
|
IdentityMap.remove(target) if IdentityMap.enabled? && target
|
48
48
|
@target = nil
|
49
|
+
@stale_state = nil
|
49
50
|
end
|
50
51
|
|
51
52
|
# Reloads the \target and returns +self+ on success.
|
@@ -128,16 +129,21 @@ module ActiveRecord
|
|
128
129
|
# This method is abstract in the sense that it relies on +find_target+,
|
129
130
|
# which is expected to be provided by descendants.
|
130
131
|
#
|
131
|
-
# If the \target is
|
132
|
-
#
|
132
|
+
# If the \target is stale(the target no longer points to the record(s) that the
|
133
|
+
# relevant foreign_key(s) refers to.), force reload the \target.
|
134
|
+
#
|
135
|
+
# Otherwise if the \target is already \loaded it is just returned. Thus, you can
|
136
|
+
# call +load_target+ unconditionally to get the \target.
|
133
137
|
#
|
134
138
|
# ActiveRecord::RecordNotFound is rescued within the method, and it is
|
135
139
|
# not reraised. The proxy is \reset and +nil+ is the return value.
|
136
140
|
def load_target
|
137
|
-
if find_target?
|
141
|
+
if (@stale_state && stale_target?) || find_target?
|
138
142
|
begin
|
139
143
|
if IdentityMap.enabled? && association_class && association_class.respond_to?(:base_class)
|
140
144
|
@target = IdentityMap.get(association_class, owner[reflection.foreign_key])
|
145
|
+
elsif @stale_state && stale_target?
|
146
|
+
@target = find_target
|
141
147
|
end
|
142
148
|
rescue NameError
|
143
149
|
nil
|
@@ -34,7 +34,10 @@ module ActiveRecord::Associations::Builder
|
|
34
34
|
method_name = "belongs_to_counter_cache_before_destroy_for_#{name}"
|
35
35
|
mixin.redefine_method(method_name) do
|
36
36
|
record = send(name)
|
37
|
-
|
37
|
+
|
38
|
+
if record && !self.destroyed?
|
39
|
+
record.class.decrement_counter(cache_column, record.id)
|
40
|
+
end
|
38
41
|
end
|
39
42
|
model.before_destroy(method_name)
|
40
43
|
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'active_support/core_ext/object/inclusion'
|
2
|
+
|
3
|
+
module ActiveRecord::Associations::Builder
|
4
|
+
class BelongsTo < SingularAssociation #:nodoc:
|
5
|
+
self.macro = :belongs_to
|
6
|
+
|
7
|
+
self.valid_options += [:foreign_type, :polymorphic, :touch]
|
8
|
+
|
9
|
+
def constructable?
|
10
|
+
!options[:polymorphic]
|
11
|
+
end
|
12
|
+
|
13
|
+
def build
|
14
|
+
reflection = super
|
15
|
+
add_counter_cache_callbacks(reflection) if options[:counter_cache]
|
16
|
+
add_touch_callbacks(reflection) if options[:touch]
|
17
|
+
configure_dependency
|
18
|
+
reflection
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def add_counter_cache_callbacks(reflection)
|
24
|
+
cache_column = reflection.counter_cache_column
|
25
|
+
name = self.name
|
26
|
+
|
27
|
+
<<<<<<< HEAD
|
28
|
+
method_name = "belongs_to_counter_cache_after_create_for_#{name}"
|
29
|
+
mixin.redefine_method(method_name) do
|
30
|
+
record = send(name)
|
31
|
+
record.class.increment_counter(cache_column, record.id) unless record.nil?
|
32
|
+
=======
|
33
|
+
def belongs_to_counter_cache_before_destroy_for_#{name}
|
34
|
+
unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == #{foreign_key.to_sym.inspect}
|
35
|
+
record = #{name}
|
36
|
+
if record && !self.destroyed?
|
37
|
+
record.class.decrement_counter(:#{cache_column}, record.id)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
>>>>>>> 19d32e8... Merge pull request #10489 from greenriver/ar_counter_cache_multiple_destroy
|
41
|
+
end
|
42
|
+
model.after_create(method_name)
|
43
|
+
|
44
|
+
method_name = "belongs_to_counter_cache_before_destroy_for_#{name}"
|
45
|
+
mixin.redefine_method(method_name) do
|
46
|
+
record = send(name)
|
47
|
+
record.class.decrement_counter(cache_column, record.id) unless record.nil?
|
48
|
+
end
|
49
|
+
model.before_destroy(method_name)
|
50
|
+
|
51
|
+
model.send(:module_eval,
|
52
|
+
"#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)", __FILE__, __LINE__
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_touch_callbacks(reflection)
|
57
|
+
name = self.name
|
58
|
+
method_name = "belongs_to_touch_after_save_or_destroy_for_#{name}"
|
59
|
+
touch = options[:touch]
|
60
|
+
|
61
|
+
mixin.redefine_method(method_name) do
|
62
|
+
record = send(name)
|
63
|
+
|
64
|
+
unless record.nil?
|
65
|
+
if touch == true
|
66
|
+
record.touch
|
67
|
+
else
|
68
|
+
record.touch(touch)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
model.after_save(method_name)
|
74
|
+
model.after_touch(method_name)
|
75
|
+
model.after_destroy(method_name)
|
76
|
+
end
|
77
|
+
|
78
|
+
def configure_dependency
|
79
|
+
if options[:dependent]
|
80
|
+
unless options[:dependent].in?([:destroy, :delete])
|
81
|
+
raise ArgumentError, "The :dependent option expects either :destroy or :delete (#{options[:dependent].inspect})"
|
82
|
+
end
|
83
|
+
|
84
|
+
method_name = "belongs_to_dependent_#{options[:dependent]}_for_#{name}"
|
85
|
+
model.send(:class_eval, <<-eoruby, __FILE__, __LINE__ + 1)
|
86
|
+
def #{method_name}
|
87
|
+
association = #{name}
|
88
|
+
association.#{options[:dependent]} if association
|
89
|
+
end
|
90
|
+
eoruby
|
91
|
+
model.after_destroy method_name
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -43,7 +43,7 @@ module ActiveRecord
|
|
43
43
|
|
44
44
|
# Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
|
45
45
|
def ids_reader
|
46
|
-
if loaded? || options[:finder_sql]
|
46
|
+
if owner.new_record? || loaded? || options[:finder_sql]
|
47
47
|
load_target.map do |record|
|
48
48
|
record.send(reflection.association_primary_key)
|
49
49
|
end
|
@@ -89,8 +89,7 @@ module ActiveRecord
|
|
89
89
|
records.each { |r| r.destroy }
|
90
90
|
update_counter(-records.length) unless inverse_updates_counter_cache?
|
91
91
|
else
|
92
|
-
|
93
|
-
scope = scoped.where(reflection.association_primary_key => keys)
|
92
|
+
scope = self.scoped.where(reflection.klass.primary_key => records)
|
94
93
|
|
95
94
|
if method == :delete_all
|
96
95
|
update_counter(-scope.delete_all)
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
# = Active Record Has Many Association
|
3
|
+
module Associations
|
4
|
+
# This is the proxy that handles a has many association.
|
5
|
+
#
|
6
|
+
# If the association has a <tt>:through</tt> option further specialization
|
7
|
+
# is provided by its child HasManyThroughAssociation.
|
8
|
+
class HasManyAssociation < CollectionAssociation #:nodoc:
|
9
|
+
|
10
|
+
def insert_record(record, validate = true, raise = false)
|
11
|
+
set_owner_attributes(record)
|
12
|
+
|
13
|
+
if raise
|
14
|
+
record.save!(:validate => validate)
|
15
|
+
else
|
16
|
+
record.save(:validate => validate)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Returns the number of records in this collection.
|
23
|
+
#
|
24
|
+
# If the association has a counter cache it gets that value. Otherwise
|
25
|
+
# it will attempt to do a count via SQL, bounded to <tt>:limit</tt> if
|
26
|
+
# there's one. Some configuration options like :group make it impossible
|
27
|
+
# to do an SQL count, in those cases the array count will be used.
|
28
|
+
#
|
29
|
+
# That does not depend on whether the collection has already been loaded
|
30
|
+
# or not. The +size+ method is the one that takes the loaded flag into
|
31
|
+
# account and delegates to +count_records+ if needed.
|
32
|
+
#
|
33
|
+
# If the collection is empty the target is set to an empty array and
|
34
|
+
# the loaded flag is set to true as well.
|
35
|
+
def count_records
|
36
|
+
count = if has_cached_counter?
|
37
|
+
owner.send(:read_attribute, cached_counter_attribute_name)
|
38
|
+
elsif options[:counter_sql] || options[:finder_sql]
|
39
|
+
reflection.klass.count_by_sql(custom_counter_sql)
|
40
|
+
else
|
41
|
+
scoped.count
|
42
|
+
end
|
43
|
+
|
44
|
+
# If there's nothing in the database and @target has no new records
|
45
|
+
# we are certain the current target is an empty array. This is a
|
46
|
+
# documented side-effect of the method that may avoid an extra SELECT.
|
47
|
+
@target ||= [] and loaded! if count == 0
|
48
|
+
|
49
|
+
[options[:limit], count].compact.min
|
50
|
+
end
|
51
|
+
|
52
|
+
def has_cached_counter?(reflection = reflection)
|
53
|
+
owner.attribute_present?(cached_counter_attribute_name(reflection))
|
54
|
+
end
|
55
|
+
|
56
|
+
def cached_counter_attribute_name(reflection = reflection)
|
57
|
+
"#{reflection.name}_count"
|
58
|
+
end
|
59
|
+
|
60
|
+
def update_counter(difference, reflection = reflection)
|
61
|
+
if has_cached_counter?(reflection)
|
62
|
+
counter = cached_counter_attribute_name(reflection)
|
63
|
+
owner.class.update_counters(owner.id, counter => difference)
|
64
|
+
owner[counter] += difference
|
65
|
+
owner.changed_attributes.delete(counter) # eww
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# This shit is nasty. We need to avoid the following situation:
|
70
|
+
#
|
71
|
+
# * An associated record is deleted via record.destroy
|
72
|
+
# * Hence the callbacks run, and they find a belongs_to on the record with a
|
73
|
+
# :counter_cache options which points back at our owner. So they update the
|
74
|
+
# counter cache.
|
75
|
+
# * In which case, we must make sure to *not* update the counter cache, or else
|
76
|
+
# it will be decremented twice.
|
77
|
+
#
|
78
|
+
# Hence this method.
|
79
|
+
def inverse_updates_counter_cache?(reflection = reflection)
|
80
|
+
counter_name = cached_counter_attribute_name(reflection)
|
81
|
+
reflection.klass.reflect_on_all_associations(:belongs_to).any? { |inverse_reflection|
|
82
|
+
inverse_reflection.counter_cache_column == counter_name
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
# Deletes the records according to the <tt>:dependent</tt> option.
|
87
|
+
def delete_records(records, method)
|
88
|
+
if method == :destroy
|
89
|
+
records.each { |r| r.destroy }
|
90
|
+
update_counter(-records.length) unless inverse_updates_counter_cache?
|
91
|
+
else
|
92
|
+
<<<<<<< HEAD
|
93
|
+
keys = records.map { |r| r[reflection.association_primary_key] }
|
94
|
+
scope = scoped.where(reflection.association_primary_key => keys)
|
95
|
+
=======
|
96
|
+
if records == :all
|
97
|
+
scope = self.scope
|
98
|
+
else
|
99
|
+
scope = self.scope.where(reflection.klass.primary_key => records)
|
100
|
+
end
|
101
|
+
>>>>>>> 030d30d... Merge pull request #10713 from senny/10693_fix_primary_key_option_on_has_many
|
102
|
+
|
103
|
+
if method == :delete_all
|
104
|
+
update_counter(-scope.delete_all)
|
105
|
+
else
|
106
|
+
update_counter(-scope.update_all(reflection.foreign_key => nil))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def foreign_key_present?
|
112
|
+
owner.attribute_present?(reflection.association_primary_key)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|