activerecord 4.2.11.3 → 5.0.0.beta1
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 +1029 -1349
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/examples/performance.rb +2 -2
- data/lib/active_record.rb +7 -3
- data/lib/active_record/aggregations.rb +35 -25
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations.rb +305 -204
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +10 -8
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +20 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +41 -18
- data/lib/active_record/associations/builder/collection_association.rb +8 -24
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +10 -5
- data/lib/active_record/associations/builder/singular_association.rb +2 -9
- data/lib/active_record/associations/collection_association.rb +40 -43
- data/lib/active_record/associations/collection_proxy.rb +55 -29
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +20 -71
- data/lib/active_record/associations/has_many_through_association.rb +8 -52
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +28 -18
- data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
- data/lib/active_record/associations/preloader.rb +13 -4
- data/lib/active_record/associations/preloader/association.rb +45 -51
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +5 -4
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/attribute.rb +61 -17
- data/lib/active_record/attribute/user_provided_default.rb +23 -0
- data/lib/active_record/attribute_assignment.rb +27 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +79 -26
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +26 -42
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
- data/lib/active_record/attribute_methods/write.rb +13 -24
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attributes.rb +194 -81
- data/lib/active_record/autosave_association.rb +33 -15
- data/lib/active_record/base.rb +30 -18
- data/lib/active_record/callbacks.rb +36 -40
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +31 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
- data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
- data/lib/active_record/connection_adapters/column.rb +27 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
- data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
- data/lib/active_record/connection_handling.rb +5 -5
- data/lib/active_record/core.rb +72 -104
- data/lib/active_record/counter_cache.rb +9 -20
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +110 -76
- data/lib/active_record/errors.rb +72 -47
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +19 -4
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +27 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +10 -14
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +40 -22
- data/lib/active_record/migration.rb +304 -133
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +90 -0
- data/lib/active_record/model_schema.rb +92 -40
- data/lib/active_record/nested_attributes.rb +45 -34
- data/lib/active_record/null_relation.rb +15 -7
- data/lib/active_record/persistence.rb +112 -72
- data/lib/active_record/querying.rb +6 -5
- data/lib/active_record/railtie.rb +20 -13
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +47 -38
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +182 -57
- data/lib/active_record/relation.rb +152 -100
- data/lib/active_record/relation/batches.rb +133 -33
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +80 -101
- data/lib/active_record/relation/delegation.rb +6 -19
- data/lib/active_record/relation/finder_methods.rb +58 -46
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +13 -42
- data/lib/active_record/relation/predicate_builder.rb +99 -105
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +274 -238
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -6
- data/lib/active_record/relation/where_clause.rb +173 -0
- data/lib/active_record/relation/where_clause_factory.rb +37 -0
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +94 -65
- data/lib/active_record/schema.rb +23 -22
- data/lib/active_record/schema_dumper.rb +33 -22
- data/lib/active_record/schema_migration.rb +10 -4
- data/lib/active_record/scoping.rb +17 -6
- data/lib/active_record/scoping/default.rb +19 -6
- data/lib/active_record/scoping/named.rb +39 -28
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +15 -13
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +54 -0
- data/lib/active_record/table_metadata.rb +64 -0
- data/lib/active_record/tasks/database_tasks.rb +30 -40
- data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +16 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +138 -56
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +9 -14
- data/lib/active_record/type/time.rb +3 -21
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +24 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +36 -0
- data/lib/active_record/validations/presence.rb +12 -12
- data/lib/active_record/validations/uniqueness.rb +24 -21
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +50 -35
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'active_support/core_ext/module/attribute_accessors'
|
2
|
-
|
3
1
|
# This is the parent Association class which defines the variables
|
4
2
|
# used by all associations.
|
5
3
|
#
|
@@ -11,19 +9,14 @@ require 'active_support/core_ext/module/attribute_accessors'
|
|
11
9
|
# - CollectionAssociation
|
12
10
|
# - HasManyAssociation
|
13
11
|
|
14
|
-
module ActiveRecord::Associations::Builder
|
12
|
+
module ActiveRecord::Associations::Builder # :nodoc:
|
15
13
|
class Association #:nodoc:
|
16
14
|
class << self
|
17
15
|
attr_accessor :extensions
|
18
|
-
# TODO: This class accessor is needed to make activerecord-deprecated_finders work.
|
19
|
-
# We can move it to a constant in 5.0.
|
20
|
-
attr_accessor :valid_options
|
21
16
|
end
|
22
17
|
self.extensions = []
|
23
18
|
|
24
|
-
|
25
|
-
|
26
|
-
attr_reader :name, :scope, :options
|
19
|
+
VALID_OPTIONS = [:class_name, :anonymous_class, :foreign_key, :validate] # :nodoc:
|
27
20
|
|
28
21
|
def self.build(model, name, scope, options, &block)
|
29
22
|
if model.dangerous_attribute_method?(name)
|
@@ -32,57 +25,60 @@ module ActiveRecord::Associations::Builder
|
|
32
25
|
"Please choose a different association name."
|
33
26
|
end
|
34
27
|
|
35
|
-
|
36
|
-
reflection =
|
28
|
+
extension = define_extensions model, name, &block
|
29
|
+
reflection = create_reflection model, name, scope, options, extension
|
37
30
|
define_accessors model, reflection
|
38
31
|
define_callbacks model, reflection
|
39
32
|
define_validations model, reflection
|
40
|
-
builder.define_extensions model
|
41
33
|
reflection
|
42
34
|
end
|
43
35
|
|
44
|
-
def self.
|
36
|
+
def self.create_reflection(model, name, scope, options, extension = nil)
|
45
37
|
raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
|
46
38
|
|
47
|
-
new(model, name, scope, options, &block)
|
48
|
-
end
|
49
|
-
|
50
|
-
def initialize(model, name, scope, options)
|
51
|
-
# TODO: Move this to create_builder as soon we drop support to activerecord-deprecated_finders.
|
52
39
|
if scope.is_a?(Hash)
|
53
40
|
options = scope
|
54
41
|
scope = nil
|
55
42
|
end
|
56
43
|
|
57
|
-
|
58
|
-
@name = name
|
59
|
-
@scope = scope
|
60
|
-
@options = options
|
44
|
+
validate_options(options)
|
61
45
|
|
62
|
-
|
46
|
+
scope = build_scope(scope, extension)
|
47
|
+
|
48
|
+
ActiveRecord::Reflection.create(macro, name, scope, options, model)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.build_scope(scope, extension)
|
52
|
+
new_scope = scope
|
63
53
|
|
64
54
|
if scope && scope.arity == 0
|
65
|
-
|
55
|
+
new_scope = proc { instance_exec(&scope) }
|
56
|
+
end
|
57
|
+
|
58
|
+
if extension
|
59
|
+
new_scope = wrap_scope new_scope, extension
|
66
60
|
end
|
61
|
+
|
62
|
+
new_scope
|
67
63
|
end
|
68
64
|
|
69
|
-
def
|
70
|
-
|
65
|
+
def self.wrap_scope(scope, extension)
|
66
|
+
scope
|
71
67
|
end
|
72
68
|
|
73
|
-
def macro
|
69
|
+
def self.macro
|
74
70
|
raise NotImplementedError
|
75
71
|
end
|
76
72
|
|
77
|
-
def valid_options
|
78
|
-
|
73
|
+
def self.valid_options(options)
|
74
|
+
VALID_OPTIONS + Association.extensions.flat_map(&:valid_options)
|
79
75
|
end
|
80
76
|
|
81
|
-
def validate_options
|
82
|
-
options.assert_valid_keys(valid_options)
|
77
|
+
def self.validate_options(options)
|
78
|
+
options.assert_valid_keys(valid_options(options))
|
83
79
|
end
|
84
80
|
|
85
|
-
def define_extensions(model)
|
81
|
+
def self.define_extensions(model, name)
|
86
82
|
end
|
87
83
|
|
88
84
|
def self.define_callbacks(model, reflection)
|
@@ -133,8 +129,6 @@ module ActiveRecord::Associations::Builder
|
|
133
129
|
raise NotImplementedError
|
134
130
|
end
|
135
131
|
|
136
|
-
private
|
137
|
-
|
138
132
|
def self.check_dependent_options(dependent)
|
139
133
|
unless valid_dependent_options.include? dependent
|
140
134
|
raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{dependent}"
|
@@ -1,11 +1,11 @@
|
|
1
|
-
module ActiveRecord::Associations::Builder
|
1
|
+
module ActiveRecord::Associations::Builder # :nodoc:
|
2
2
|
class BelongsTo < SingularAssociation #:nodoc:
|
3
|
-
def macro
|
3
|
+
def self.macro
|
4
4
|
:belongs_to
|
5
5
|
end
|
6
6
|
|
7
|
-
def valid_options
|
8
|
-
super + [:foreign_type, :polymorphic, :touch, :counter_cache]
|
7
|
+
def self.valid_options(options)
|
8
|
+
super + [:foreign_type, :polymorphic, :touch, :counter_cache, :optional]
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.valid_dependent_options
|
@@ -23,8 +23,6 @@ module ActiveRecord::Associations::Builder
|
|
23
23
|
add_counter_cache_methods mixin
|
24
24
|
end
|
25
25
|
|
26
|
-
private
|
27
|
-
|
28
26
|
def self.add_counter_cache_methods(mixin)
|
29
27
|
return if mixin.method_defined? :belongs_to_counter_cache_after_update
|
30
28
|
|
@@ -35,16 +33,24 @@ module ActiveRecord::Associations::Builder
|
|
35
33
|
|
36
34
|
if (@_after_create_counter_called ||= false)
|
37
35
|
@_after_create_counter_called = false
|
38
|
-
elsif attribute_changed?(foreign_key) && !new_record?
|
39
|
-
|
36
|
+
elsif attribute_changed?(foreign_key) && !new_record?
|
37
|
+
if reflection.polymorphic?
|
38
|
+
model = attribute(reflection.foreign_type).try(:constantize)
|
39
|
+
model_was = attribute_was(reflection.foreign_type).try(:constantize)
|
40
|
+
else
|
41
|
+
model = reflection.klass
|
42
|
+
model_was = reflection.klass
|
43
|
+
end
|
44
|
+
|
40
45
|
foreign_key_was = attribute_was foreign_key
|
41
46
|
foreign_key = attribute foreign_key
|
42
47
|
|
43
48
|
if foreign_key && model.respond_to?(:increment_counter)
|
44
49
|
model.increment_counter(cache_column, foreign_key)
|
45
50
|
end
|
46
|
-
|
47
|
-
|
51
|
+
|
52
|
+
if foreign_key_was && model_was.respond_to?(:decrement_counter)
|
53
|
+
model_was.decrement_counter(cache_column, foreign_key_was)
|
48
54
|
end
|
49
55
|
end
|
50
56
|
end
|
@@ -62,7 +68,7 @@ module ActiveRecord::Associations::Builder
|
|
62
68
|
klass.attr_readonly cache_column if klass && klass.respond_to?(:attr_readonly)
|
63
69
|
end
|
64
70
|
|
65
|
-
def self.touch_record(o, foreign_key, name, touch) # :nodoc:
|
71
|
+
def self.touch_record(o, foreign_key, name, touch, touch_method) # :nodoc:
|
66
72
|
old_foreign_id = o.changed_attributes[foreign_key]
|
67
73
|
|
68
74
|
if old_foreign_id
|
@@ -77,9 +83,9 @@ module ActiveRecord::Associations::Builder
|
|
77
83
|
|
78
84
|
if old_record
|
79
85
|
if touch != true
|
80
|
-
old_record.
|
86
|
+
old_record.send(touch_method, touch)
|
81
87
|
else
|
82
|
-
old_record.
|
88
|
+
old_record.send(touch_method)
|
83
89
|
end
|
84
90
|
end
|
85
91
|
end
|
@@ -87,9 +93,9 @@ module ActiveRecord::Associations::Builder
|
|
87
93
|
record = o.send name
|
88
94
|
if record && record.persisted?
|
89
95
|
if touch != true
|
90
|
-
record.
|
96
|
+
record.send(touch_method, touch)
|
91
97
|
else
|
92
|
-
record.
|
98
|
+
record.send(touch_method)
|
93
99
|
end
|
94
100
|
end
|
95
101
|
end
|
@@ -100,7 +106,7 @@ module ActiveRecord::Associations::Builder
|
|
100
106
|
touch = reflection.options[:touch]
|
101
107
|
|
102
108
|
callback = lambda { |record|
|
103
|
-
BelongsTo.touch_record(record, foreign_key, n, touch)
|
109
|
+
BelongsTo.touch_record(record, foreign_key, n, touch, belongs_to_touch_method)
|
104
110
|
}
|
105
111
|
|
106
112
|
model.after_save callback, if: :changed?
|
@@ -109,8 +115,25 @@ module ActiveRecord::Associations::Builder
|
|
109
115
|
end
|
110
116
|
|
111
117
|
def self.add_destroy_callbacks(model, reflection)
|
112
|
-
|
113
|
-
|
118
|
+
model.after_destroy lambda { |o| o.association(reflection.name).handle_dependency }
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.define_validations(model, reflection)
|
122
|
+
if reflection.options.key?(:required)
|
123
|
+
reflection.options[:optional] = !reflection.options.delete(:required)
|
124
|
+
end
|
125
|
+
|
126
|
+
if reflection.options[:optional].nil?
|
127
|
+
required = model.belongs_to_required_by_default
|
128
|
+
else
|
129
|
+
required = !reflection.options[:optional]
|
130
|
+
end
|
131
|
+
|
132
|
+
super
|
133
|
+
|
134
|
+
if required
|
135
|
+
model.validates_presence_of reflection.name, message: :required
|
136
|
+
end
|
114
137
|
end
|
115
138
|
end
|
116
139
|
end
|
@@ -2,27 +2,16 @@
|
|
2
2
|
|
3
3
|
require 'active_record/associations'
|
4
4
|
|
5
|
-
module ActiveRecord::Associations::Builder
|
5
|
+
module ActiveRecord::Associations::Builder # :nodoc:
|
6
6
|
class CollectionAssociation < Association #:nodoc:
|
7
7
|
|
8
8
|
CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
|
9
9
|
|
10
|
-
def valid_options
|
10
|
+
def self.valid_options(options)
|
11
11
|
super + [:table_name, :before_add,
|
12
12
|
:after_add, :before_remove, :after_remove, :extend]
|
13
13
|
end
|
14
14
|
|
15
|
-
attr_reader :block_extension
|
16
|
-
|
17
|
-
def initialize(model, name, scope, options)
|
18
|
-
super
|
19
|
-
@mod = nil
|
20
|
-
if block_given?
|
21
|
-
@mod = Module.new(&Proc.new)
|
22
|
-
@scope = wrap_scope @scope, @mod
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
15
|
def self.define_callbacks(model, reflection)
|
27
16
|
super
|
28
17
|
name = reflection.name
|
@@ -32,10 +21,11 @@ module ActiveRecord::Associations::Builder
|
|
32
21
|
}
|
33
22
|
end
|
34
23
|
|
35
|
-
def define_extensions(model)
|
36
|
-
if
|
24
|
+
def self.define_extensions(model, name)
|
25
|
+
if block_given?
|
37
26
|
extension_module_name = "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
|
38
|
-
|
27
|
+
extension = Module.new(&Proc.new)
|
28
|
+
model.parent.const_set(extension_module_name, extension)
|
39
29
|
end
|
40
30
|
end
|
41
31
|
|
@@ -78,15 +68,9 @@ module ActiveRecord::Associations::Builder
|
|
78
68
|
CODE
|
79
69
|
end
|
80
70
|
|
81
|
-
|
82
|
-
|
83
|
-
def wrap_scope(scope, mod)
|
71
|
+
def self.wrap_scope(scope, mod)
|
84
72
|
if scope
|
85
|
-
|
86
|
-
proc { |owner| instance_exec(owner, &scope).extending(mod) }
|
87
|
-
else
|
88
|
-
proc { instance_exec(&scope).extending(mod) }
|
89
|
-
end
|
73
|
+
proc { |owner| instance_exec(owner, &scope).extending(mod) }
|
90
74
|
else
|
91
75
|
proc { extending(mod) }
|
92
76
|
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
module ActiveRecord::Associations::Builder
|
1
|
+
module ActiveRecord::Associations::Builder # :nodoc:
|
2
2
|
class HasAndBelongsToMany # :nodoc:
|
3
|
-
class JoinTableResolver
|
3
|
+
class JoinTableResolver # :nodoc:
|
4
4
|
KnownTable = Struct.new :join_table
|
5
5
|
|
6
|
-
class KnownClass
|
6
|
+
class KnownClass # :nodoc:
|
7
7
|
def initialize(lhs_class, rhs_class_name)
|
8
8
|
@lhs_class = lhs_class
|
9
9
|
@rhs_class_name = rhs_class_name
|
@@ -62,13 +62,13 @@ module ActiveRecord::Associations::Builder
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def self.add_left_association(name, options)
|
65
|
-
belongs_to name, options
|
65
|
+
belongs_to name, required: false, **options
|
66
66
|
self.left_reflection = _reflect_on_association(name)
|
67
67
|
end
|
68
68
|
|
69
69
|
def self.add_right_association(name, options)
|
70
70
|
rhs_name = name.to_s.singularize.to_sym
|
71
|
-
belongs_to rhs_name, options
|
71
|
+
belongs_to rhs_name, required: false, **options
|
72
72
|
self.right_reflection = _reflect_on_association(rhs_name)
|
73
73
|
end
|
74
74
|
|
@@ -89,13 +89,13 @@ module ActiveRecord::Associations::Builder
|
|
89
89
|
|
90
90
|
def middle_reflection(join_model)
|
91
91
|
middle_name = [lhs_model.name.downcase.pluralize,
|
92
|
-
association_name].join('_').gsub(
|
92
|
+
association_name].join('_'.freeze).gsub('::'.freeze, '_'.freeze).to_sym
|
93
93
|
middle_options = middle_options join_model
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
94
|
+
|
95
|
+
HasMany.create_reflection(lhs_model,
|
96
|
+
middle_name,
|
97
|
+
nil,
|
98
|
+
middle_options)
|
99
99
|
end
|
100
100
|
|
101
101
|
private
|
@@ -1,11 +1,11 @@
|
|
1
|
-
module ActiveRecord::Associations::Builder
|
1
|
+
module ActiveRecord::Associations::Builder # :nodoc:
|
2
2
|
class HasMany < CollectionAssociation #:nodoc:
|
3
|
-
def macro
|
3
|
+
def self.macro
|
4
4
|
:has_many
|
5
5
|
end
|
6
6
|
|
7
|
-
def valid_options
|
8
|
-
super + [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :counter_cache, :join_table, :foreign_type]
|
7
|
+
def self.valid_options(options)
|
8
|
+
super + [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :counter_cache, :join_table, :foreign_type, :index_errors]
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.valid_dependent_options
|
@@ -1,10 +1,10 @@
|
|
1
|
-
module ActiveRecord::Associations::Builder
|
1
|
+
module ActiveRecord::Associations::Builder # :nodoc:
|
2
2
|
class HasOne < SingularAssociation #:nodoc:
|
3
|
-
def macro
|
3
|
+
def self.macro
|
4
4
|
:has_one
|
5
5
|
end
|
6
6
|
|
7
|
-
def valid_options
|
7
|
+
def self.valid_options(options)
|
8
8
|
valid = super + [:as, :foreign_type]
|
9
9
|
valid += [:through, :source, :source_type] if options[:through]
|
10
10
|
valid
|
@@ -14,10 +14,15 @@ module ActiveRecord::Associations::Builder
|
|
14
14
|
[:destroy, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
|
15
15
|
end
|
16
16
|
|
17
|
-
private
|
18
|
-
|
19
17
|
def self.add_destroy_callbacks(model, reflection)
|
20
18
|
super unless reflection.options[:through]
|
21
19
|
end
|
20
|
+
|
21
|
+
def self.define_validations(model, reflection)
|
22
|
+
super
|
23
|
+
if reflection.options[:required]
|
24
|
+
model.validates_presence_of reflection.name, message: :required
|
25
|
+
end
|
26
|
+
end
|
22
27
|
end
|
23
28
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# This class is inherited by the has_one and belongs_to association classes
|
2
2
|
|
3
|
-
module ActiveRecord::Associations::Builder
|
3
|
+
module ActiveRecord::Associations::Builder # :nodoc:
|
4
4
|
class SingularAssociation < Association #:nodoc:
|
5
|
-
def valid_options
|
5
|
+
def self.valid_options(options)
|
6
6
|
super + [:dependent, :primary_key, :inverse_of, :required]
|
7
7
|
end
|
8
8
|
|
@@ -27,12 +27,5 @@ module ActiveRecord::Associations::Builder
|
|
27
27
|
end
|
28
28
|
CODE
|
29
29
|
end
|
30
|
-
|
31
|
-
def self.define_validations(model, reflection)
|
32
|
-
super
|
33
|
-
if reflection.options[:required]
|
34
|
-
model.validates_presence_of reflection.name
|
35
|
-
end
|
36
|
-
end
|
37
30
|
end
|
38
31
|
end
|
@@ -28,15 +28,21 @@ module ActiveRecord
|
|
28
28
|
# Implements the reader method, e.g. foo.items for Foo.has_many :items
|
29
29
|
def reader(force_reload = false)
|
30
30
|
if force_reload
|
31
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
32
|
+
Passing an argument to force an association to reload is now
|
33
|
+
deprecated and will be removed in Rails 5.1. Please call `reload`
|
34
|
+
on the result collection proxy instead.
|
35
|
+
MSG
|
36
|
+
|
31
37
|
klass.uncached { reload }
|
32
38
|
elsif stale_target?
|
33
39
|
reload
|
34
40
|
end
|
35
41
|
|
36
|
-
if
|
42
|
+
if null_scope?
|
37
43
|
# Cache the proxy separately before the owner has an id
|
38
44
|
# or else a post-save proxy will still lack the id
|
39
|
-
@
|
45
|
+
@null_proxy ||= CollectionProxy.create(klass, self)
|
40
46
|
else
|
41
47
|
@proxy ||= CollectionProxy.create(klass, self)
|
42
48
|
end
|
@@ -54,28 +60,19 @@ module ActiveRecord
|
|
54
60
|
record.send(reflection.association_primary_key)
|
55
61
|
end
|
56
62
|
else
|
57
|
-
|
58
|
-
|
63
|
+
@association_ids ||= (
|
64
|
+
column = "#{reflection.quoted_table_name}.#{reflection.association_primary_key}"
|
65
|
+
scope.pluck(column)
|
66
|
+
)
|
59
67
|
end
|
60
68
|
end
|
61
69
|
|
62
70
|
# Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
|
63
71
|
def ids_writer(ids)
|
64
|
-
|
65
|
-
|
66
|
-
ids
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
objs = klass.where(pk_column => ids).index_by do |r|
|
71
|
-
r.send(pk_column)
|
72
|
-
end.values_at(*ids).compact
|
73
|
-
|
74
|
-
if objs.size == ids.size
|
75
|
-
replace(objs.index_by { |r| r.send(pk_column) }.values_at(*ids))
|
76
|
-
else
|
77
|
-
klass.all.raise_record_not_found_exception!(ids, objs.size, ids.size)
|
78
|
-
end
|
72
|
+
pk_type = reflection.primary_key_type
|
73
|
+
ids = Array(ids).reject(&:blank?)
|
74
|
+
ids.map! { |i| pk_type.cast(i) }
|
75
|
+
replace(klass.find(ids).index_by(&:id).values_at(*ids))
|
79
76
|
end
|
80
77
|
|
81
78
|
def reset
|
@@ -172,6 +169,7 @@ module ActiveRecord
|
|
172
169
|
# be chained. Since << flattens its argument list and inserts each record,
|
173
170
|
# +push+ and +concat+ behave identically.
|
174
171
|
def concat(*records)
|
172
|
+
records = records.flatten
|
175
173
|
if owner.new_record?
|
176
174
|
load_target
|
177
175
|
concat_records(records)
|
@@ -239,11 +237,7 @@ module ActiveRecord
|
|
239
237
|
|
240
238
|
# Count all records using SQL. Construct options and pass them with
|
241
239
|
# scope to the target class's +count+.
|
242
|
-
def count(column_name = nil
|
243
|
-
# TODO: Remove count_options argument as soon we remove support to
|
244
|
-
# activerecord-deprecated_finders.
|
245
|
-
column_name, count_options = nil, column_name if column_name.is_a?(Hash)
|
246
|
-
|
240
|
+
def count(column_name = nil)
|
247
241
|
relation = scope
|
248
242
|
if association_scope.distinct_value
|
249
243
|
# This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
|
@@ -275,7 +269,7 @@ module ActiveRecord
|
|
275
269
|
_options = records.extract_options!
|
276
270
|
dependent = _options[:dependent] || options[:dependent]
|
277
271
|
|
278
|
-
records = find(records) if records.any? { |record| record.kind_of?(
|
272
|
+
records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
|
279
273
|
delete_or_destroy(records, dependent)
|
280
274
|
end
|
281
275
|
|
@@ -286,7 +280,7 @@ module ActiveRecord
|
|
286
280
|
# +:dependent+ option.
|
287
281
|
def destroy(*records)
|
288
282
|
return if records.empty?
|
289
|
-
records = find(records) if records.any? { |record| record.kind_of?(
|
283
|
+
records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
|
290
284
|
delete_or_destroy(records, :destroy)
|
291
285
|
end
|
292
286
|
|
@@ -310,7 +304,7 @@ module ActiveRecord
|
|
310
304
|
elsif !loaded? && !association_scope.group_values.empty?
|
311
305
|
load_target.size
|
312
306
|
elsif !loaded? && !association_scope.distinct_value && target.is_a?(Array)
|
313
|
-
unsaved_records = target.select
|
307
|
+
unsaved_records = target.select(&:new_record?)
|
314
308
|
unsaved_records.size + count_records
|
315
309
|
else
|
316
310
|
count_records
|
@@ -343,7 +337,8 @@ module ActiveRecord
|
|
343
337
|
end
|
344
338
|
|
345
339
|
# Returns true if the collections is not empty.
|
346
|
-
#
|
340
|
+
# If block given, loads all records and checks for one or more matches.
|
341
|
+
# Otherwise, equivalent to +!collection.empty?+.
|
347
342
|
def any?
|
348
343
|
if block_given?
|
349
344
|
load_target.any? { |*block_args| yield(*block_args) }
|
@@ -353,7 +348,8 @@ module ActiveRecord
|
|
353
348
|
end
|
354
349
|
|
355
350
|
# Returns true if the collection has more than 1 record.
|
356
|
-
#
|
351
|
+
# If block given, loads all records and checks for two or more matches.
|
352
|
+
# Otherwise, equivalent to +collection.size > 1+.
|
357
353
|
def many?
|
358
354
|
if block_given?
|
359
355
|
load_target.many? { |*block_args| yield(*block_args) }
|
@@ -382,6 +378,8 @@ module ActiveRecord
|
|
382
378
|
replace_common_records_in_memory(other_array, original_target)
|
383
379
|
if other_array != original_target
|
384
380
|
transaction { replace_records(other_array, original_target) }
|
381
|
+
else
|
382
|
+
other_array
|
385
383
|
end
|
386
384
|
end
|
387
385
|
end
|
@@ -416,12 +414,16 @@ module ActiveRecord
|
|
416
414
|
|
417
415
|
def replace_on_target(record, index, skip_callbacks)
|
418
416
|
callback(:before_add, record) unless skip_callbacks
|
417
|
+
|
418
|
+
was_loaded = loaded?
|
419
419
|
yield(record) if block_given?
|
420
420
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
421
|
+
unless !was_loaded && loaded?
|
422
|
+
if index
|
423
|
+
@target[index] = record
|
424
|
+
else
|
425
|
+
@target << record
|
426
|
+
end
|
425
427
|
end
|
426
428
|
|
427
429
|
callback(:after_add, record) unless skip_callbacks
|
@@ -521,7 +523,7 @@ module ActiveRecord
|
|
521
523
|
def delete_or_destroy(records, method)
|
522
524
|
records = records.flatten
|
523
525
|
records.each { |record| raise_on_type_mismatch!(record) }
|
524
|
-
existing_records = records.reject
|
526
|
+
existing_records = records.reject(&:new_record?)
|
525
527
|
|
526
528
|
if existing_records.empty?
|
527
529
|
remove_records(existing_records, records, method)
|
@@ -568,7 +570,7 @@ module ActiveRecord
|
|
568
570
|
def concat_records(records, should_raise = false)
|
569
571
|
result = true
|
570
572
|
|
571
|
-
records.
|
573
|
+
records.each do |record|
|
572
574
|
raise_on_type_mismatch!(record)
|
573
575
|
add_to_target(record) do |rec|
|
574
576
|
result &&= insert_record(rec, true, should_raise) unless owner.new_record?
|
@@ -612,13 +614,8 @@ module ActiveRecord
|
|
612
614
|
if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
613
615
|
assoc = owner.association(reflection.through_reflection.name)
|
614
616
|
assoc.reader.any? { |source|
|
615
|
-
|
616
|
-
|
617
|
-
if target_association.respond_to?(:include?)
|
618
|
-
target_association.include?(record)
|
619
|
-
else
|
620
|
-
target_association == record
|
621
|
-
end
|
617
|
+
target_reflection = source.send(reflection.source_reflection.name)
|
618
|
+
target_reflection.respond_to?(:include?) ? target_reflection.include?(record) : target_reflection == record
|
622
619
|
} || target.include?(record)
|
623
620
|
else
|
624
621
|
target.include?(record)
|
@@ -629,7 +626,7 @@ module ActiveRecord
|
|
629
626
|
# specified, then #find scans the entire collection.
|
630
627
|
def find_by_scan(*args)
|
631
628
|
expects_array = args.first.kind_of?(Array)
|
632
|
-
ids = args.flatten.compact.map
|
629
|
+
ids = args.flatten.compact.map(&:to_s).uniq
|
633
630
|
|
634
631
|
if ids.size == 1
|
635
632
|
id = ids.first
|