activerecord 5.0.7 → 5.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
|