activerecord 5.0.7 → 5.1.7
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 +5 -5
- data/CHANGELOG.md +657 -2080
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +28 -28
- data/examples/simple.rb +3 -3
- data/lib/active_record/aggregations.rb +244 -244
- data/lib/active_record/association_relation.rb +5 -5
- data/lib/active_record/associations/alias_tracker.rb +10 -11
- data/lib/active_record/associations/association.rb +23 -5
- data/lib/active_record/associations/association_scope.rb +95 -81
- data/lib/active_record/associations/belongs_to_association.rb +7 -4
- data/lib/active_record/associations/builder/belongs_to.rb +30 -16
- data/lib/active_record/associations/builder/collection_association.rb +1 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
- data/lib/active_record/associations/collection_association.rb +36 -205
- data/lib/active_record/associations/collection_proxy.rb +132 -63
- data/lib/active_record/associations/has_many_association.rb +10 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -4
- data/lib/active_record/associations/has_one_association.rb +24 -28
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
- data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +121 -118
- data/lib/active_record/associations/preloader/association.rb +64 -64
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
- data/lib/active_record/associations/preloader/collection_association.rb +6 -6
- data/lib/active_record/associations/preloader/has_many.rb +0 -2
- data/lib/active_record/associations/preloader/singular_association.rb +6 -8
- data/lib/active_record/associations/preloader/through_association.rb +41 -41
- data/lib/active_record/associations/preloader.rb +94 -94
- data/lib/active_record/associations/singular_association.rb +8 -25
- data/lib/active_record/associations/through_association.rb +2 -5
- data/lib/active_record/associations.rb +1591 -1562
- data/lib/active_record/attribute/user_provided_default.rb +4 -2
- data/lib/active_record/attribute.rb +98 -71
- data/lib/active_record/attribute_assignment.rb +61 -61
- data/lib/active_record/attribute_decorators.rb +35 -13
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +229 -46
- data/lib/active_record/attribute_methods/primary_key.rb +74 -73
- data/lib/active_record/attribute_methods/read.rb +39 -35
- data/lib/active_record/attribute_methods/serialization.rb +7 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
- data/lib/active_record/attribute_methods/write.rb +30 -33
- data/lib/active_record/attribute_methods.rb +56 -65
- data/lib/active_record/attribute_mutation_tracker.rb +63 -11
- data/lib/active_record/attribute_set/builder.rb +27 -33
- data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_record/attribute_set.rb +9 -6
- data/lib/active_record/attributes.rb +22 -22
- data/lib/active_record/autosave_association.rb +18 -13
- data/lib/active_record/base.rb +24 -22
- data/lib/active_record/callbacks.rb +56 -14
- data/lib/active_record/coders/yaml_column.rb +9 -11
- data/lib/active_record/collection_cache_key.rb +3 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
- data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
- data/lib/active_record/connection_adapters/column.rb +26 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
- data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
- data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
- data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
- data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
- data/lib/active_record/connection_handling.rb +14 -26
- data/lib/active_record/core.rb +109 -93
- data/lib/active_record/counter_cache.rb +60 -13
- data/lib/active_record/define_callbacks.rb +20 -0
- data/lib/active_record/dynamic_matchers.rb +80 -79
- data/lib/active_record/enum.rb +8 -6
- data/lib/active_record/errors.rb +64 -15
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +7 -4
- data/lib/active_record/fixture_set/file.rb +11 -8
- data/lib/active_record/fixtures.rb +66 -53
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +93 -79
- data/lib/active_record/integration.rb +7 -7
- data/lib/active_record/internal_metadata.rb +3 -16
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +69 -74
- data/lib/active_record/locking/pessimistic.rb +10 -1
- data/lib/active_record/log_subscriber.rb +23 -28
- data/lib/active_record/migration/command_recorder.rb +94 -94
- data/lib/active_record/migration/compatibility.rb +100 -47
- data/lib/active_record/migration/join_table.rb +6 -6
- data/lib/active_record/migration.rb +153 -155
- data/lib/active_record/model_schema.rb +94 -107
- data/lib/active_record/nested_attributes.rb +200 -199
- data/lib/active_record/null_relation.rb +11 -34
- data/lib/active_record/persistence.rb +65 -50
- data/lib/active_record/query_cache.rb +2 -6
- data/lib/active_record/querying.rb +3 -4
- data/lib/active_record/railtie.rb +16 -17
- data/lib/active_record/railties/controller_runtime.rb +6 -2
- data/lib/active_record/railties/databases.rake +105 -133
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -2
- data/lib/active_record/reflection.rb +154 -108
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/batches.rb +80 -51
- data/lib/active_record/relation/calculations.rb +169 -162
- data/lib/active_record/relation/delegation.rb +32 -31
- data/lib/active_record/relation/finder_methods.rb +197 -231
- data/lib/active_record/relation/merger.rb +58 -62
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
- data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder.rb +92 -89
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +255 -293
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +4 -5
- data/lib/active_record/relation/where_clause.rb +80 -65
- data/lib/active_record/relation/where_clause_factory.rb +47 -8
- data/lib/active_record/relation.rb +93 -119
- data/lib/active_record/result.rb +41 -32
- data/lib/active_record/runtime_registry.rb +3 -3
- data/lib/active_record/sanitization.rb +176 -192
- data/lib/active_record/schema.rb +3 -3
- data/lib/active_record/schema_dumper.rb +15 -38
- data/lib/active_record/schema_migration.rb +8 -4
- data/lib/active_record/scoping/default.rb +90 -90
- data/lib/active_record/scoping/named.rb +11 -11
- data/lib/active_record/scoping.rb +6 -6
- data/lib/active_record/secure_token.rb +2 -2
- data/lib/active_record/statement_cache.rb +13 -15
- data/lib/active_record/store.rb +31 -32
- data/lib/active_record/suppressor.rb +2 -1
- data/lib/active_record/table_metadata.rb +9 -5
- data/lib/active_record/tasks/database_tasks.rb +65 -55
- data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
- data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
- data/lib/active_record/timestamp.rb +46 -25
- data/lib/active_record/touch_later.rb +1 -2
- data/lib/active_record/transactions.rb +97 -109
- data/lib/active_record/type/adapter_specific_registry.rb +46 -42
- data/lib/active_record/type/decimal_without_scale.rb +13 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
- data/lib/active_record/type/internal/abstract_json.rb +4 -0
- data/lib/active_record/type/serialized.rb +14 -8
- data/lib/active_record/type/text.rb +9 -0
- data/lib/active_record/type/time.rb +0 -1
- data/lib/active_record/type/type_map.rb +11 -15
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type.rb +17 -13
- data/lib/active_record/type_caster/connection.rb +8 -6
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +8 -39
- data/lib/active_record/validations.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +20 -20
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
- data/lib/rails/generators/active_record/migration.rb +1 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
- data/lib/rails/generators/active_record.rb +4 -4
- metadata +24 -13
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "active_support/core_ext/array/wrap"
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Associations
|
@@ -19,7 +19,7 @@ module ActiveRecord
|
|
19
19
|
attr_reader :owner, :target, :reflection
|
20
20
|
attr_accessor :inversed
|
21
21
|
|
22
|
-
delegate :options, :
|
22
|
+
delegate :options, to: :reflection
|
23
23
|
|
24
24
|
def initialize(owner, reflection)
|
25
25
|
reflection.check_validity!
|
@@ -112,6 +112,15 @@ module ActiveRecord
|
|
112
112
|
record
|
113
113
|
end
|
114
114
|
|
115
|
+
# Remove the inverse association, if possible
|
116
|
+
def remove_inverse_instance(record)
|
117
|
+
if invertible_for?(record)
|
118
|
+
inverse = record.association(inverse_reflection_for(record).name)
|
119
|
+
inverse.target = nil
|
120
|
+
inverse.inversed = false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
115
124
|
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
|
116
125
|
# polymorphic_type field on the owner.
|
117
126
|
def klass
|
@@ -176,13 +185,21 @@ module ActiveRecord
|
|
176
185
|
def initialize_attributes(record, except_from_scope_attributes = nil) #:nodoc:
|
177
186
|
except_from_scope_attributes ||= {}
|
178
187
|
skip_assign = [reflection.foreign_key, reflection.type].compact
|
179
|
-
assigned_keys = record.
|
188
|
+
assigned_keys = record.changed_attribute_names_to_save
|
180
189
|
assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
|
181
190
|
attributes = create_scope.except(*(assigned_keys - skip_assign))
|
182
191
|
record.assign_attributes(attributes)
|
183
192
|
set_inverse_instance(record)
|
184
193
|
end
|
185
194
|
|
195
|
+
def create(attributes = {}, &block)
|
196
|
+
_create_record(attributes, &block)
|
197
|
+
end
|
198
|
+
|
199
|
+
def create!(attributes = {}, &block)
|
200
|
+
_create_record(attributes, true, &block)
|
201
|
+
end
|
202
|
+
|
186
203
|
private
|
187
204
|
|
188
205
|
def find_target?
|
@@ -227,7 +244,8 @@ module ActiveRecord
|
|
227
244
|
unless record.is_a?(reflection.klass)
|
228
245
|
fresh_class = reflection.class_name.safe_constantize
|
229
246
|
unless fresh_class && record.is_a?(fresh_class)
|
230
|
-
message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected,
|
247
|
+
message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, "\
|
248
|
+
"got #{record.inspect} which is an instance of #{record.class}(##{record.class.object_id})"
|
231
249
|
raise ActiveRecord::AssociationTypeMismatch, message
|
232
250
|
end
|
233
251
|
end
|
@@ -255,7 +273,7 @@ module ActiveRecord
|
|
255
273
|
# so that when stale_state is different from the value stored on the last find_target,
|
256
274
|
# the target is stale.
|
257
275
|
#
|
258
|
-
# This is only relevant to certain associations, which is why it returns nil by default.
|
276
|
+
# This is only relevant to certain associations, which is why it returns +nil+ by default.
|
259
277
|
def stale_state
|
260
278
|
end
|
261
279
|
|
@@ -21,11 +21,11 @@ module ActiveRecord
|
|
21
21
|
reflection = association.reflection
|
22
22
|
scope = klass.unscoped
|
23
23
|
owner = association.owner
|
24
|
-
alias_tracker = AliasTracker.create connection, association.klass.table_name
|
24
|
+
alias_tracker = AliasTracker.create connection, association.klass.table_name
|
25
25
|
chain_head, chain_tail = get_chain(reflection, association, alias_tracker)
|
26
26
|
|
27
27
|
scope.extending! reflection.extensions
|
28
|
-
add_constraints(scope, owner,
|
28
|
+
add_constraints(scope, owner, reflection, chain_head, chain_tail)
|
29
29
|
end
|
30
30
|
|
31
31
|
def join_type
|
@@ -49,118 +49,132 @@ module ActiveRecord
|
|
49
49
|
binds
|
50
50
|
end
|
51
51
|
|
52
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
53
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
52
54
|
protected
|
53
55
|
|
54
|
-
|
56
|
+
attr_reader :value_transformation
|
55
57
|
|
56
58
|
private
|
57
|
-
|
58
|
-
|
59
|
-
|
59
|
+
def join(table, constraint)
|
60
|
+
table.create_join(table, table.create_on(constraint), join_type)
|
61
|
+
end
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
63
|
+
def last_chain_scope(scope, table, reflection, owner)
|
64
|
+
join_keys = reflection.join_keys
|
65
|
+
key = join_keys.key
|
66
|
+
foreign_key = join_keys.foreign_key
|
65
67
|
|
66
|
-
|
67
|
-
|
68
|
+
value = transform_value(owner[foreign_key])
|
69
|
+
scope = apply_scope(scope, table, key, value)
|
68
70
|
|
69
|
-
|
70
|
-
|
71
|
-
|
71
|
+
if reflection.type
|
72
|
+
polymorphic_type = transform_value(owner.class.base_class.name)
|
73
|
+
scope = apply_scope(scope, table, reflection.type, polymorphic_type)
|
74
|
+
end
|
75
|
+
|
76
|
+
scope
|
72
77
|
end
|
73
78
|
|
74
|
-
|
75
|
-
|
79
|
+
def transform_value(value)
|
80
|
+
value_transformation.call(value)
|
81
|
+
end
|
76
82
|
|
77
|
-
|
78
|
-
|
79
|
-
|
83
|
+
def next_chain_scope(scope, table, reflection, foreign_table, next_reflection)
|
84
|
+
join_keys = reflection.join_keys
|
85
|
+
key = join_keys.key
|
86
|
+
foreign_key = join_keys.foreign_key
|
80
87
|
|
81
|
-
|
82
|
-
join_keys = reflection.join_keys(association_klass)
|
83
|
-
key = join_keys.key
|
84
|
-
foreign_key = join_keys.foreign_key
|
88
|
+
constraint = table[key].eq(foreign_table[foreign_key])
|
85
89
|
|
86
|
-
|
90
|
+
if reflection.type
|
91
|
+
value = transform_value(next_reflection.klass.base_class.name)
|
92
|
+
scope = apply_scope(scope, table, reflection.type, value)
|
93
|
+
end
|
87
94
|
|
88
|
-
|
89
|
-
value = transform_value(next_reflection.klass.base_class.name)
|
90
|
-
scope = scope.where(table.name => { reflection.type => value })
|
95
|
+
scope.joins!(join(foreign_table, constraint))
|
91
96
|
end
|
92
97
|
|
93
|
-
|
94
|
-
|
98
|
+
class ReflectionProxy < SimpleDelegator # :nodoc:
|
99
|
+
attr_accessor :next
|
100
|
+
attr_reader :alias_name
|
95
101
|
|
96
|
-
|
97
|
-
|
98
|
-
|
102
|
+
def initialize(reflection, alias_name)
|
103
|
+
super(reflection)
|
104
|
+
@alias_name = alias_name
|
105
|
+
end
|
99
106
|
|
100
|
-
|
101
|
-
super(reflection)
|
102
|
-
@alias_name = alias_name
|
107
|
+
def all_includes; nil; end
|
103
108
|
end
|
104
109
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
110
|
+
def get_chain(reflection, association, tracker)
|
111
|
+
name = reflection.name
|
112
|
+
runtime_reflection = Reflection::RuntimeReflection.new(reflection, association)
|
113
|
+
previous_reflection = runtime_reflection
|
114
|
+
reflection.chain.drop(1).each do |refl|
|
115
|
+
alias_name = tracker.aliased_table_for(
|
116
|
+
refl.table_name,
|
117
|
+
refl.alias_candidate(name),
|
118
|
+
refl.klass.type_caster
|
119
|
+
)
|
120
|
+
proxy = ReflectionProxy.new(refl, alias_name)
|
121
|
+
previous_reflection.next = proxy
|
122
|
+
previous_reflection = proxy
|
123
|
+
end
|
124
|
+
[runtime_reflection, previous_reflection]
|
117
125
|
end
|
118
|
-
[runtime_reflection, previous_reflection]
|
119
|
-
end
|
120
126
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
127
|
+
def add_constraints(scope, owner, refl, chain_head, chain_tail)
|
128
|
+
owner_reflection = chain_tail
|
129
|
+
table = owner_reflection.alias_name
|
130
|
+
scope = last_chain_scope(scope, table, owner_reflection, owner)
|
125
131
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
table = reflection.alias_name
|
130
|
-
|
131
|
-
unless reflection == chain_tail
|
132
|
+
reflection = chain_head
|
133
|
+
while reflection
|
134
|
+
table = reflection.alias_name
|
132
135
|
next_reflection = reflection.next
|
133
|
-
foreign_table = next_reflection.alias_name
|
134
|
-
scope = next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
|
135
|
-
end
|
136
136
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
item = eval_scope(reflection.klass, scope_chain_item, owner)
|
141
|
-
|
142
|
-
if scope_chain_item == refl.scope
|
143
|
-
scope.merge! item.except(:where, :includes)
|
137
|
+
unless reflection == chain_tail
|
138
|
+
foreign_table = next_reflection.alias_name
|
139
|
+
scope = next_chain_scope(scope, table, reflection, foreign_table, next_reflection)
|
144
140
|
end
|
145
141
|
|
146
|
-
|
147
|
-
|
142
|
+
# Exclude the scope of the association itself, because that
|
143
|
+
# was already merged in the #scope method.
|
144
|
+
reflection.constraints.each do |scope_chain_item|
|
145
|
+
item = eval_scope(reflection.klass, table, scope_chain_item, owner)
|
146
|
+
|
147
|
+
if scope_chain_item == refl.scope
|
148
|
+
scope.merge! item.except(:where, :includes)
|
149
|
+
end
|
150
|
+
|
151
|
+
reflection.all_includes do
|
152
|
+
scope.includes! item.includes_values
|
153
|
+
end
|
154
|
+
|
155
|
+
scope.unscope!(*item.unscope_values)
|
156
|
+
scope.where_clause += item.where_clause
|
157
|
+
scope.order_values |= item.order_values
|
148
158
|
end
|
149
159
|
|
150
|
-
|
151
|
-
scope.where_clause += item.where_clause
|
152
|
-
scope.order_values |= item.order_values
|
160
|
+
reflection = next_reflection
|
153
161
|
end
|
154
162
|
|
155
|
-
|
163
|
+
scope
|
156
164
|
end
|
157
165
|
|
158
|
-
scope
|
159
|
-
|
166
|
+
def apply_scope(scope, table, key, value)
|
167
|
+
if scope.table == table
|
168
|
+
scope.where!(key => value)
|
169
|
+
else
|
170
|
+
scope.where!(table.name => { key => value })
|
171
|
+
end
|
172
|
+
end
|
160
173
|
|
161
|
-
|
162
|
-
|
163
|
-
|
174
|
+
def eval_scope(klass, table, scope, owner)
|
175
|
+
predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table))
|
176
|
+
ActiveRecord::Relation.create(klass, table, predicate_builder).instance_exec(owner, &scope)
|
177
|
+
end
|
164
178
|
end
|
165
179
|
end
|
166
180
|
end
|
@@ -2,7 +2,6 @@ module ActiveRecord
|
|
2
2
|
# = Active Record Belongs To Association
|
3
3
|
module Associations
|
4
4
|
class BelongsToAssociation < SingularAssociation #:nodoc:
|
5
|
-
|
6
5
|
def handle_dependency
|
7
6
|
target.send(options[:dependent]) if load_target
|
8
7
|
end
|
@@ -22,6 +21,10 @@ module ActiveRecord
|
|
22
21
|
self.target = record
|
23
22
|
end
|
24
23
|
|
24
|
+
def default(&block)
|
25
|
+
writer(owner.instance_exec(&block)) if reader.nil?
|
26
|
+
end
|
27
|
+
|
25
28
|
def reset
|
26
29
|
super
|
27
30
|
@updated = false
|
@@ -44,9 +47,9 @@ module ActiveRecord
|
|
44
47
|
def update_counters(by)
|
45
48
|
if require_counter_update? && foreign_key_present?
|
46
49
|
if target && !stale_target?
|
47
|
-
target.increment!(reflection.counter_cache_column, by)
|
50
|
+
target.increment!(reflection.counter_cache_column, by, touch: reflection.options[:touch])
|
48
51
|
else
|
49
|
-
klass.update_counters(target_id, reflection.counter_cache_column => by)
|
52
|
+
klass.update_counters(target_id, reflection.counter_cache_column => by, touch: reflection.options[:touch])
|
50
53
|
end
|
51
54
|
end
|
52
55
|
end
|
@@ -62,7 +65,7 @@ module ActiveRecord
|
|
62
65
|
def update_counters_on_replace(record)
|
63
66
|
if require_counter_update? && different_target?(record)
|
64
67
|
owner.instance_variable_set :@_after_replace_counter_called, true
|
65
|
-
record.increment!(reflection.counter_cache_column)
|
68
|
+
record.increment!(reflection.counter_cache_column, touch: reflection.options[:touch])
|
66
69
|
decrement_counters
|
67
70
|
end
|
68
71
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def self.valid_options(options)
|
8
|
-
super + [:polymorphic, :touch, :counter_cache, :optional]
|
8
|
+
super + [:polymorphic, :touch, :counter_cache, :optional, :default]
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.valid_dependent_options
|
@@ -16,6 +16,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
16
16
|
super
|
17
17
|
add_counter_cache_callbacks(model, reflection) if reflection.options[:counter_cache]
|
18
18
|
add_touch_callbacks(model, reflection) if reflection.options[:touch]
|
19
|
+
add_default_callbacks(model, reflection) if reflection.options[:default]
|
19
20
|
end
|
20
21
|
|
21
22
|
def self.define_accessors(mixin, reflection)
|
@@ -35,17 +36,17 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
35
36
|
@_after_create_counter_called = false
|
36
37
|
elsif (@_after_replace_counter_called ||= false)
|
37
38
|
@_after_replace_counter_called = false
|
38
|
-
elsif
|
39
|
+
elsif saved_change_to_attribute?(foreign_key) && !new_record?
|
39
40
|
if reflection.polymorphic?
|
40
|
-
model =
|
41
|
-
model_was =
|
41
|
+
model = attribute_in_database(reflection.foreign_type).try(:constantize)
|
42
|
+
model_was = attribute_before_last_save(reflection.foreign_type).try(:constantize)
|
42
43
|
else
|
43
44
|
model = reflection.klass
|
44
45
|
model_was = reflection.klass
|
45
46
|
end
|
46
47
|
|
47
|
-
foreign_key_was =
|
48
|
-
foreign_key =
|
48
|
+
foreign_key_was = attribute_before_last_save foreign_key
|
49
|
+
foreign_key = attribute_in_database foreign_key
|
49
50
|
|
50
51
|
if foreign_key && model.respond_to?(:increment_counter)
|
51
52
|
model.increment_counter(cache_column, foreign_key)
|
@@ -70,18 +71,21 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
70
71
|
klass.attr_readonly cache_column if klass && klass.respond_to?(:attr_readonly)
|
71
72
|
end
|
72
73
|
|
73
|
-
def self.touch_record(o, foreign_key, name, touch, touch_method) # :nodoc:
|
74
|
-
old_foreign_id =
|
74
|
+
def self.touch_record(o, changes, foreign_key, name, touch, touch_method) # :nodoc:
|
75
|
+
old_foreign_id = changes[foreign_key] && changes[foreign_key].first
|
75
76
|
|
76
77
|
if old_foreign_id
|
77
78
|
association = o.association(name)
|
78
79
|
reflection = association.reflection
|
79
80
|
if reflection.polymorphic?
|
80
|
-
|
81
|
+
foreign_type = reflection.foreign_type
|
82
|
+
klass = changes[foreign_type] && changes[foreign_type].first || o.public_send(foreign_type)
|
83
|
+
klass = klass.constantize
|
81
84
|
else
|
82
85
|
klass = association.klass
|
83
86
|
end
|
84
|
-
|
87
|
+
primary_key = reflection.association_primary_key(klass)
|
88
|
+
old_record = klass.find_by(primary_key => old_foreign_id)
|
85
89
|
|
86
90
|
if old_record
|
87
91
|
if touch != true
|
@@ -107,13 +111,23 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
107
111
|
n = reflection.name
|
108
112
|
touch = reflection.options[:touch]
|
109
113
|
|
110
|
-
callback = lambda { |record|
|
111
|
-
BelongsTo.touch_record(record, foreign_key, n, touch, belongs_to_touch_method)
|
112
|
-
}
|
114
|
+
callback = lambda { |changes_method| lambda { |record|
|
115
|
+
BelongsTo.touch_record(record, record.send(changes_method), foreign_key, n, touch, belongs_to_touch_method)
|
116
|
+
}}
|
117
|
+
|
118
|
+
unless reflection.counter_cache_column
|
119
|
+
model.after_create callback.(:saved_changes), if: :saved_changes?
|
120
|
+
model.after_destroy callback.(:changes_to_save)
|
121
|
+
end
|
113
122
|
|
114
|
-
model.
|
115
|
-
model.after_touch
|
116
|
-
|
123
|
+
model.after_update callback.(:saved_changes), if: :saved_changes?
|
124
|
+
model.after_touch callback.(:changes_to_save)
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.add_default_callbacks(model, reflection)
|
128
|
+
model.before_validation lambda { |o|
|
129
|
+
o.association(reflection.name).default(&reflection.options[:default])
|
130
|
+
}
|
117
131
|
end
|
118
132
|
|
119
133
|
def self.add_destroy_callbacks(model, reflection)
|
@@ -1,10 +1,9 @@
|
|
1
1
|
# This class is inherited by the has_many and has_many_and_belongs_to_many association classes
|
2
2
|
|
3
|
-
require
|
3
|
+
require "active_record/associations"
|
4
4
|
|
5
5
|
module ActiveRecord::Associations::Builder # :nodoc:
|
6
6
|
class CollectionAssociation < Association #:nodoc:
|
7
|
-
|
8
7
|
CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
|
9
8
|
|
10
9
|
def self.valid_options(options)
|
@@ -16,9 +16,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
def klass
|
20
|
+
@lhs_class.send(:compute_type, @rhs_class_name)
|
21
|
+
end
|
22
22
|
end
|
23
23
|
|
24
24
|
def self.build(lhs_class, name, options)
|
@@ -28,7 +28,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
28
28
|
class_name = options.fetch(:class_name) {
|
29
29
|
name.to_s.camelize.singularize
|
30
30
|
}
|
31
|
-
KnownClass.new lhs_class, class_name
|
31
|
+
KnownClass.new lhs_class, class_name.to_s
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -78,9 +78,9 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
78
78
|
|
79
79
|
private
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
81
|
+
def self.suppress_composite_primary_key(pk)
|
82
|
+
pk unless pk.is_a?(Array)
|
83
|
+
end
|
84
84
|
}
|
85
85
|
|
86
86
|
join_model.name = "HABTM_#{association_name.to_s.camelize}"
|
@@ -94,7 +94,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
94
94
|
|
95
95
|
def middle_reflection(join_model)
|
96
96
|
middle_name = [lhs_model.name.downcase.pluralize,
|
97
|
-
association_name].join(
|
97
|
+
association_name].join("_".freeze).gsub("::".freeze, "_".freeze).to_sym
|
98
98
|
middle_options = middle_options join_model
|
99
99
|
|
100
100
|
HasMany.create_reflection(lhs_model,
|
@@ -105,29 +105,29 @@ module ActiveRecord::Associations::Builder # :nodoc:
|
|
105
105
|
|
106
106
|
private
|
107
107
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
108
|
+
def middle_options(join_model)
|
109
|
+
middle_options = {}
|
110
|
+
middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
|
111
|
+
middle_options[:source] = join_model.left_reflection.name
|
112
|
+
if options.key? :foreign_key
|
113
|
+
middle_options[:foreign_key] = options[:foreign_key]
|
114
|
+
end
|
115
|
+
middle_options
|
114
116
|
end
|
115
|
-
middle_options
|
116
|
-
end
|
117
117
|
|
118
|
-
|
119
|
-
|
118
|
+
def belongs_to_options(options)
|
119
|
+
rhs_options = {}
|
120
120
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
121
|
+
if options.key? :class_name
|
122
|
+
rhs_options[:foreign_key] = options[:class_name].to_s.foreign_key
|
123
|
+
rhs_options[:class_name] = options[:class_name]
|
124
|
+
end
|
125
125
|
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
if options.key? :association_foreign_key
|
127
|
+
rhs_options[:foreign_key] = options[:association_foreign_key]
|
128
|
+
end
|
129
129
|
|
130
|
-
|
131
|
-
|
130
|
+
rhs_options
|
131
|
+
end
|
132
132
|
end
|
133
133
|
end
|