activerecord 3.1.12 → 3.2.22.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 +804 -338
- data/README.rdoc +3 -3
- data/examples/performance.rb +20 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +3 -6
- data/lib/active_record/associations/association.rb +13 -45
- data/lib/active_record/associations/association_scope.rb +3 -15
- 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/association.rb +6 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -4
- data/lib/active_record/associations/builder/collection_association.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +5 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -16
- data/lib/active_record/associations/collection_association.rb +65 -32
- data/lib/active_record/associations/collection_proxy.rb +8 -41
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +1 -0
- data/lib/active_record/associations/has_many_association.rb +11 -7
- data/lib/active_record/associations/has_many_through_association.rb +19 -9
- data/lib/active_record/associations/has_one_association.rb +23 -13
- data/lib/active_record/associations/join_dependency/join_association.rb +6 -1
- data/lib/active_record/associations/join_dependency.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +3 -3
- data/lib/active_record/associations/preloader.rb +14 -10
- data/lib/active_record/associations/through_association.rb +8 -4
- data/lib/active_record/associations.rb +92 -76
- data/lib/active_record/attribute_assignment.rb +221 -0
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
- data/lib/active_record/attribute_methods/dirty.rb +21 -11
- data/lib/active_record/attribute_methods/primary_key.rb +62 -25
- data/lib/active_record/attribute_methods/read.rb +73 -83
- data/lib/active_record/attribute_methods/serialization.rb +120 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attribute_methods/write.rb +32 -6
- data/lib/active_record/attribute_methods.rb +231 -30
- data/lib/active_record/autosave_association.rb +44 -26
- data/lib/active_record/base.rb +227 -1708
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +150 -148
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +85 -29
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +7 -34
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +10 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +7 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +39 -28
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -19
- data/lib/active_record/connection_adapters/abstract_adapter.rb +77 -42
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +676 -0
- data/lib/active_record/connection_adapters/column.rb +37 -11
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +133 -581
- data/lib/active_record/connection_adapters/mysql_adapter.rb +136 -693
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +209 -97
- data/lib/active_record/connection_adapters/schema_cache.rb +69 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -6
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +62 -35
- data/lib/active_record/counter_cache.rb +9 -4
- data/lib/active_record/dynamic_finder_match.rb +12 -0
- data/lib/active_record/dynamic_matchers.rb +84 -0
- data/lib/active_record/errors.rb +11 -1
- data/lib/active_record/explain.rb +86 -0
- data/lib/active_record/explain_subscriber.rb +25 -0
- data/lib/active_record/fixtures/file.rb +65 -0
- data/lib/active_record/fixtures.rb +57 -86
- data/lib/active_record/identity_map.rb +3 -4
- data/lib/active_record/inheritance.rb +174 -0
- data/lib/active_record/integration.rb +60 -0
- data/lib/active_record/locking/optimistic.rb +33 -26
- data/lib/active_record/locking/pessimistic.rb +23 -1
- data/lib/active_record/log_subscriber.rb +8 -4
- data/lib/active_record/migration/command_recorder.rb +8 -8
- data/lib/active_record/migration.rb +68 -35
- data/lib/active_record/model_schema.rb +368 -0
- data/lib/active_record/nested_attributes.rb +60 -24
- data/lib/active_record/persistence.rb +57 -11
- data/lib/active_record/query_cache.rb +6 -6
- data/lib/active_record/querying.rb +58 -0
- data/lib/active_record/railtie.rb +37 -29
- data/lib/active_record/railties/controller_runtime.rb +3 -1
- data/lib/active_record/railties/databases.rake +213 -117
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +26 -0
- data/lib/active_record/reflection.rb +7 -15
- data/lib/active_record/relation/batches.rb +7 -4
- data/lib/active_record/relation/calculations.rb +55 -16
- data/lib/active_record/relation/delegation.rb +49 -0
- data/lib/active_record/relation/finder_methods.rb +16 -11
- data/lib/active_record/relation/predicate_builder.rb +8 -6
- data/lib/active_record/relation/query_methods.rb +75 -9
- data/lib/active_record/relation/spawn_methods.rb +48 -7
- data/lib/active_record/relation.rb +78 -32
- data/lib/active_record/result.rb +10 -4
- data/lib/active_record/sanitization.rb +194 -0
- data/lib/active_record/schema_dumper.rb +12 -5
- data/lib/active_record/scoping/default.rb +142 -0
- data/lib/active_record/scoping/named.rb +200 -0
- data/lib/active_record/scoping.rb +152 -0
- data/lib/active_record/serialization.rb +1 -43
- data/lib/active_record/serializers/xml_serializer.rb +4 -45
- data/lib/active_record/session_store.rb +18 -16
- data/lib/active_record/store.rb +52 -0
- data/lib/active_record/test_case.rb +11 -7
- data/lib/active_record/timestamp.rb +17 -3
- data/lib/active_record/transactions.rb +27 -6
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/validations/associated.rb +5 -4
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record/validations.rb +1 -1
- data/lib/active_record/version.rb +3 -3
- data/lib/active_record.rb +38 -3
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +12 -3
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -1
- data/lib/rails/generators/active_record/model/templates/migration.rb +3 -5
- data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
- metadata +49 -28
- data/lib/active_record/named_scope.rb +0 -200
@@ -1,12 +1,5 @@
|
|
1
|
-
require 'active_support/deprecation'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
module Associations
|
5
|
-
AssociationCollection = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
|
6
|
-
'ActiveRecord::Associations::AssociationCollection',
|
7
|
-
'ActiveRecord::Associations::CollectionProxy'
|
8
|
-
)
|
9
|
-
|
10
3
|
# Association proxies in Active Record are middlemen between the object that
|
11
4
|
# holds the association, known as the <tt>@owner</tt>, and the actual associated
|
12
5
|
# object, known as the <tt>@target</tt>. The kind of association any proxy is
|
@@ -46,7 +39,7 @@ module ActiveRecord
|
|
46
39
|
instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to|proxy_/ }
|
47
40
|
|
48
41
|
delegate :group, :order, :limit, :joins, :where, :preload, :eager_load, :includes, :from,
|
49
|
-
:lock, :readonly, :having, :to => :scoped
|
42
|
+
:lock, :readonly, :having, :pluck, :to => :scoped
|
50
43
|
|
51
44
|
delegate :target, :load_target, :loaded?, :to => :@association
|
52
45
|
|
@@ -84,14 +77,15 @@ module ActiveRecord
|
|
84
77
|
def method_missing(method, *args, &block)
|
85
78
|
match = DynamicFinderMatch.match(method)
|
86
79
|
if match && match.instantiator?
|
87
|
-
send(:find_or_instantiator_by_attributes, match, match.attribute_names, *args) do |
|
88
|
-
proxy_association.send :set_owner_attributes,
|
89
|
-
proxy_association.send :add_to_target,
|
90
|
-
yield(
|
80
|
+
send(:find_or_instantiator_by_attributes, match, match.attribute_names, *args) do |record|
|
81
|
+
proxy_association.send :set_owner_attributes, record
|
82
|
+
proxy_association.send :add_to_target, record
|
83
|
+
yield(record) if block_given?
|
84
|
+
end.tap do |record|
|
85
|
+
proxy_association.send :set_inverse_instance, record
|
91
86
|
end
|
92
|
-
end
|
93
87
|
|
94
|
-
|
88
|
+
elsif target.respond_to?(method) || (!proxy_association.klass.respond_to?(method) && Class.respond_to?(method))
|
95
89
|
if load_target
|
96
90
|
if target.respond_to?(method)
|
97
91
|
target.send(method, *args, &block)
|
@@ -134,33 +128,6 @@ module ActiveRecord
|
|
134
128
|
proxy_association.reload
|
135
129
|
self
|
136
130
|
end
|
137
|
-
|
138
|
-
def proxy_owner
|
139
|
-
ActiveSupport::Deprecation.warn(
|
140
|
-
"Calling record.#{@association.reflection.name}.proxy_owner is deprecated. Please use " \
|
141
|
-
"record.association(:#{@association.reflection.name}).owner instead. Or, from an " \
|
142
|
-
"association extension you can access proxy_association.owner."
|
143
|
-
)
|
144
|
-
proxy_association.owner
|
145
|
-
end
|
146
|
-
|
147
|
-
def proxy_target
|
148
|
-
ActiveSupport::Deprecation.warn(
|
149
|
-
"Calling record.#{@association.reflection.name}.proxy_target is deprecated. Please use " \
|
150
|
-
"record.association(:#{@association.reflection.name}).target instead. Or, from an " \
|
151
|
-
"association extension you can access proxy_association.target."
|
152
|
-
)
|
153
|
-
proxy_association.target
|
154
|
-
end
|
155
|
-
|
156
|
-
def proxy_reflection
|
157
|
-
ActiveSupport::Deprecation.warn(
|
158
|
-
"Calling record.#{@association.reflection.name}.proxy_reflection is deprecated. Please use " \
|
159
|
-
"record.association(:#{@association.reflection.name}).reflection instead. Or, from an " \
|
160
|
-
"association extension you can access proxy_association.reflection."
|
161
|
-
)
|
162
|
-
proxy_association.reflection
|
163
|
-
end
|
164
131
|
end
|
165
132
|
end
|
166
133
|
end
|
@@ -9,6 +9,7 @@ module ActiveRecord
|
|
9
9
|
|
10
10
|
def insert_record(record, validate = true, raise = false)
|
11
11
|
set_owner_attributes(record)
|
12
|
+
set_inverse_instance(record)
|
12
13
|
|
13
14
|
if raise
|
14
15
|
record.save!(:validate => validate)
|
@@ -23,7 +24,7 @@ module ActiveRecord
|
|
23
24
|
#
|
24
25
|
# If the association has a counter cache it gets that value. Otherwise
|
25
26
|
# it will attempt to do a count via SQL, bounded to <tt>:limit</tt> if
|
26
|
-
# there's one.
|
27
|
+
# there's one. Some configuration options like :group make it impossible
|
27
28
|
# to do an SQL count, in those cases the array count will be used.
|
28
29
|
#
|
29
30
|
# That does not depend on whether the collection has already been loaded
|
@@ -49,15 +50,15 @@ module ActiveRecord
|
|
49
50
|
[options[:limit], count].compact.min
|
50
51
|
end
|
51
52
|
|
52
|
-
def has_cached_counter?(reflection = reflection)
|
53
|
+
def has_cached_counter?(reflection = self.reflection)
|
53
54
|
owner.attribute_present?(cached_counter_attribute_name(reflection))
|
54
55
|
end
|
55
56
|
|
56
|
-
def cached_counter_attribute_name(reflection = reflection)
|
57
|
+
def cached_counter_attribute_name(reflection = self.reflection)
|
57
58
|
"#{reflection.name}_count"
|
58
59
|
end
|
59
60
|
|
60
|
-
def update_counter(difference, reflection = reflection)
|
61
|
+
def update_counter(difference, reflection = self.reflection)
|
61
62
|
if has_cached_counter?(reflection)
|
62
63
|
counter = cached_counter_attribute_name(reflection)
|
63
64
|
owner.class.update_counters(owner.id, counter => difference)
|
@@ -76,7 +77,7 @@ module ActiveRecord
|
|
76
77
|
# it will be decremented twice.
|
77
78
|
#
|
78
79
|
# Hence this method.
|
79
|
-
def inverse_updates_counter_cache?(reflection = reflection)
|
80
|
+
def inverse_updates_counter_cache?(reflection = self.reflection)
|
80
81
|
counter_name = cached_counter_attribute_name(reflection)
|
81
82
|
reflection.klass.reflect_on_all_associations(:belongs_to).any? { |inverse_reflection|
|
82
83
|
inverse_reflection.counter_cache_column == counter_name
|
@@ -89,8 +90,7 @@ module ActiveRecord
|
|
89
90
|
records.each { |r| r.destroy }
|
90
91
|
update_counter(-records.length) unless inverse_updates_counter_cache?
|
91
92
|
else
|
92
|
-
|
93
|
-
scope = scoped.where(reflection.association_primary_key => keys)
|
93
|
+
scope = self.scoped.where(reflection.klass.primary_key => records)
|
94
94
|
|
95
95
|
if method == :delete_all
|
96
96
|
update_counter(-scope.delete_all)
|
@@ -99,6 +99,10 @@ module ActiveRecord
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
end
|
102
|
+
|
103
|
+
def foreign_key_present?
|
104
|
+
owner.attribute_present?(reflection.association_primary_key)
|
105
|
+
end
|
102
106
|
end
|
103
107
|
end
|
104
108
|
end
|
@@ -8,7 +8,9 @@ module ActiveRecord
|
|
8
8
|
|
9
9
|
def initialize(owner, reflection)
|
10
10
|
super
|
11
|
-
|
11
|
+
|
12
|
+
@through_records = {}
|
13
|
+
@through_association = nil
|
12
14
|
end
|
13
15
|
|
14
16
|
# Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been
|
@@ -59,7 +61,7 @@ module ActiveRecord
|
|
59
61
|
private
|
60
62
|
|
61
63
|
def through_association
|
62
|
-
owner.association(through_reflection.name)
|
64
|
+
@through_association ||= owner.association(through_reflection.name)
|
63
65
|
end
|
64
66
|
|
65
67
|
# We temporarily cache through record that has been build, because if we build a
|
@@ -71,7 +73,9 @@ module ActiveRecord
|
|
71
73
|
# association
|
72
74
|
def build_through_record(record)
|
73
75
|
@through_records[record.object_id] ||= begin
|
74
|
-
|
76
|
+
ensure_mutable
|
77
|
+
|
78
|
+
through_record = through_association.build
|
75
79
|
through_record.send("#{source_reflection.name}=", record)
|
76
80
|
through_record
|
77
81
|
end
|
@@ -122,8 +126,7 @@ module ActiveRecord
|
|
122
126
|
def delete_records(records, method)
|
123
127
|
ensure_not_nested
|
124
128
|
|
125
|
-
|
126
|
-
scope = through.scoped.where(construct_join_attributes(*records))
|
129
|
+
scope = through_association.scoped.where(construct_join_attributes(*records))
|
127
130
|
|
128
131
|
case method
|
129
132
|
when :destroy
|
@@ -134,7 +137,12 @@ module ActiveRecord
|
|
134
137
|
count = scope.delete_all
|
135
138
|
end
|
136
139
|
|
137
|
-
delete_through_records(
|
140
|
+
delete_through_records(records)
|
141
|
+
|
142
|
+
if source_reflection.options[:counter_cache]
|
143
|
+
counter = source_reflection.counter_cache_column
|
144
|
+
klass.decrement_counter counter, records.map(&:id)
|
145
|
+
end
|
138
146
|
|
139
147
|
if through_reflection.macro == :has_many && update_through_counter?(method)
|
140
148
|
update_counter(-count, through_reflection)
|
@@ -149,14 +157,16 @@ module ActiveRecord
|
|
149
157
|
candidates.find_all { |c| c.attributes.slice(*attributes.keys) == attributes }
|
150
158
|
end
|
151
159
|
|
152
|
-
def delete_through_records(
|
160
|
+
def delete_through_records(records)
|
153
161
|
records.each do |record|
|
154
162
|
through_records = through_records_for(record)
|
155
163
|
|
156
164
|
if through_reflection.macro == :has_many
|
157
|
-
through_records.each { |r|
|
165
|
+
through_records.each { |r| through_association.target.delete(r) }
|
158
166
|
else
|
159
|
-
|
167
|
+
if through_records.include?(through_association.target)
|
168
|
+
through_association.target = nil
|
169
|
+
end
|
160
170
|
end
|
161
171
|
|
162
172
|
@through_records.delete(record.object_id)
|
@@ -8,19 +8,21 @@ module ActiveRecord
|
|
8
8
|
raise_on_type_mismatch(record) if record
|
9
9
|
load_target
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
11
|
+
# If target and record are nil, or target is equal to record,
|
12
|
+
# we don't need to have transaction.
|
13
|
+
if (target || record) && target != record
|
14
|
+
transaction_if(save) do
|
15
|
+
remove_target!(options[:dependent]) if target && !target.destroyed?
|
16
|
+
|
17
|
+
if record
|
18
|
+
set_owner_attributes(record)
|
19
|
+
set_inverse_instance(record)
|
20
|
+
|
21
|
+
if owner.persisted? && save && !record.save
|
22
|
+
nullify_owner_attributes(record)
|
23
|
+
set_owner_attributes(target) if target
|
24
|
+
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
|
25
|
+
end
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -68,6 +70,14 @@ module ActiveRecord
|
|
68
70
|
def nullify_owner_attributes(record)
|
69
71
|
record[reflection.foreign_key] = nil
|
70
72
|
end
|
73
|
+
|
74
|
+
def transaction_if(value)
|
75
|
+
if value
|
76
|
+
reflection.klass.transaction { yield }
|
77
|
+
else
|
78
|
+
yield
|
79
|
+
end
|
80
|
+
end
|
71
81
|
end
|
72
82
|
end
|
73
83
|
end
|
@@ -55,7 +55,12 @@ module ActiveRecord
|
|
55
55
|
|
56
56
|
def find_parent_in(other_join_dependency)
|
57
57
|
other_join_dependency.join_parts.detect do |join_part|
|
58
|
-
parent
|
58
|
+
case parent
|
59
|
+
when JoinBase
|
60
|
+
parent.active_record == join_part.active_record
|
61
|
+
else
|
62
|
+
parent == join_part
|
63
|
+
end
|
59
64
|
end
|
60
65
|
end
|
61
66
|
|
@@ -13,7 +13,7 @@ module ActiveRecord
|
|
13
13
|
@join_parts = [JoinBase.new(base)]
|
14
14
|
@associations = {}
|
15
15
|
@reflections = []
|
16
|
-
@alias_tracker = AliasTracker.new(joins)
|
16
|
+
@alias_tracker = AliasTracker.new(base.connection, joins)
|
17
17
|
@alias_tracker.aliased_name_for(base.table_name) # Updates the count for base.table_name to 1
|
18
18
|
build(associations)
|
19
19
|
end
|
@@ -109,7 +109,7 @@ module ActiveRecord
|
|
109
109
|
case associations
|
110
110
|
when Symbol, String
|
111
111
|
reflection = parent.reflections[associations.to_s.intern] or
|
112
|
-
raise ConfigurationError, "Association named '#{ associations }' was not found; perhaps you misspelled it?"
|
112
|
+
raise ConfigurationError, "Association named '#{ associations }' was not found on #{parent.active_record.name}; perhaps you misspelled it?"
|
113
113
|
unless join_association = find_join_association(reflection, parent)
|
114
114
|
@reflections << reflection
|
115
115
|
join_association = build_join_association(reflection, parent)
|
@@ -184,7 +184,7 @@ module ActiveRecord
|
|
184
184
|
|
185
185
|
macro = join_part.reflection.macro
|
186
186
|
if macro == :has_one
|
187
|
-
return if record.association_cache.key?(join_part.reflection.name)
|
187
|
+
return record.association(join_part.reflection.name).target if record.association_cache.key?(join_part.reflection.name)
|
188
188
|
association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil?
|
189
189
|
set_target_and_inverse(join_part, association, record)
|
190
190
|
else
|
@@ -37,7 +37,8 @@ module ActiveRecord
|
|
37
37
|
through_records = Array.wrap(owner.send(through_reflection.name))
|
38
38
|
|
39
39
|
# Dont cache the association - we would only be caching a subset
|
40
|
-
if
|
40
|
+
if (preload_options != through_options) ||
|
41
|
+
(reflection.options[:source_type] && through_reflection.collection?)
|
41
42
|
owner.association(through_reflection.name).reset
|
42
43
|
end
|
43
44
|
|
@@ -55,8 +56,7 @@ module ActiveRecord
|
|
55
56
|
through_options[:include] = options[:include] || options[:source]
|
56
57
|
through_options[:conditions] = options[:conditions]
|
57
58
|
end
|
58
|
-
|
59
|
-
through_options[:order] = options[:order]
|
59
|
+
through_options[:order] = options[:order] if options.has_key?(:order)
|
60
60
|
end
|
61
61
|
|
62
62
|
through_options
|
@@ -30,17 +30,21 @@ module ActiveRecord
|
|
30
30
|
# option references an association's column), it will fallback to the table
|
31
31
|
# join strategy.
|
32
32
|
class Preloader #:nodoc:
|
33
|
-
|
34
|
-
autoload :SingularAssociation, 'active_record/associations/preloader/singular_association'
|
35
|
-
autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
|
36
|
-
autoload :ThroughAssociation, 'active_record/associations/preloader/through_association'
|
33
|
+
extend ActiveSupport::Autoload
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
35
|
+
eager_autoload do
|
36
|
+
autoload :Association, 'active_record/associations/preloader/association'
|
37
|
+
autoload :SingularAssociation, 'active_record/associations/preloader/singular_association'
|
38
|
+
autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
|
39
|
+
autoload :ThroughAssociation, 'active_record/associations/preloader/through_association'
|
40
|
+
|
41
|
+
autoload :HasMany, 'active_record/associations/preloader/has_many'
|
42
|
+
autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through'
|
43
|
+
autoload :HasOne, 'active_record/associations/preloader/has_one'
|
44
|
+
autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through'
|
45
|
+
autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many'
|
46
|
+
autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
|
47
|
+
end
|
44
48
|
|
45
49
|
attr_reader :records, :associations, :options, :model
|
46
50
|
|
@@ -37,9 +37,7 @@ module ActiveRecord
|
|
37
37
|
# situation it is more natural for the user to just create or modify their join records
|
38
38
|
# directly as required.
|
39
39
|
def construct_join_attributes(*records)
|
40
|
-
|
41
|
-
raise HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(owner, reflection)
|
42
|
-
end
|
40
|
+
ensure_mutable
|
43
41
|
|
44
42
|
join_attributes = {
|
45
43
|
source_reflection.foreign_key =>
|
@@ -64,7 +62,7 @@ module ActiveRecord
|
|
64
62
|
# properly support stale-checking for nested associations.
|
65
63
|
def stale_state
|
66
64
|
if through_reflection.macro == :belongs_to
|
67
|
-
owner[through_reflection.foreign_key].to_s
|
65
|
+
owner[through_reflection.foreign_key] && owner[through_reflection.foreign_key].to_s
|
68
66
|
end
|
69
67
|
end
|
70
68
|
|
@@ -73,6 +71,12 @@ module ActiveRecord
|
|
73
71
|
!owner[through_reflection.foreign_key].nil?
|
74
72
|
end
|
75
73
|
|
74
|
+
def ensure_mutable
|
75
|
+
if source_reflection.macro != :belongs_to
|
76
|
+
raise HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(owner, reflection)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
76
80
|
def ensure_not_nested
|
77
81
|
if reflection.nested?
|
78
82
|
raise HasManyThroughNestedAssociationsAreReadonly.new(owner, reflection)
|