activerecord 4.2.11.1 → 5.0.0
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 +1282 -1195
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +8 -4
- data/lib/active_record/aggregations.rb +35 -24
- data/lib/active_record/association_relation.rb +3 -3
- data/lib/active_record/associations.rb +317 -209
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +11 -9
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +14 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -10
- data/lib/active_record/associations/collection_association.rb +49 -41
- data/lib/active_record/associations/collection_proxy.rb +67 -27
- 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 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +29 -19
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/preloader/association.rb +46 -52
- 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 +27 -14
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/attribute.rb +68 -18
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +76 -47
- 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 +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- 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 +199 -81
- data/lib/active_record/autosave_association.rb +49 -16
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -10
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +380 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +141 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -370
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +29 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -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 +3 -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 -4
- 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 +31 -17
- 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 +26 -18
- 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 +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
- 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/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +149 -192
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +89 -107
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +113 -76
- data/lib/active_record/errors.rb +87 -48
- 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 +26 -5
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- 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 +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration.rb +363 -133
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/model_schema.rb +129 -41
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +121 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +69 -46
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +282 -115
- data/lib/active_record/relation.rb +176 -116
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +79 -108
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +163 -81
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -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/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/scoping/default.rb +23 -9
- data/lib/active_record/scoping/named.rb +49 -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 +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +57 -43
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- 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 +20 -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 +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- 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 +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +30 -29
- 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 +8 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +59 -34
- 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 + [:
|
7
|
+
def self.valid_options(options)
|
8
|
+
super + [: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,26 @@ module ActiveRecord::Associations::Builder
|
|
35
33
|
|
36
34
|
if (@_after_create_counter_called ||= false)
|
37
35
|
@_after_create_counter_called = false
|
38
|
-
elsif
|
39
|
-
|
36
|
+
elsif (@_after_replace_counter_called ||= false)
|
37
|
+
@_after_replace_counter_called = false
|
38
|
+
elsif attribute_changed?(foreign_key) && !new_record?
|
39
|
+
if reflection.polymorphic?
|
40
|
+
model = attribute(reflection.foreign_type).try(:constantize)
|
41
|
+
model_was = attribute_was(reflection.foreign_type).try(:constantize)
|
42
|
+
else
|
43
|
+
model = reflection.klass
|
44
|
+
model_was = reflection.klass
|
45
|
+
end
|
46
|
+
|
40
47
|
foreign_key_was = attribute_was foreign_key
|
41
48
|
foreign_key = attribute foreign_key
|
42
49
|
|
43
50
|
if foreign_key && model.respond_to?(:increment_counter)
|
44
51
|
model.increment_counter(cache_column, foreign_key)
|
45
52
|
end
|
46
|
-
|
47
|
-
|
53
|
+
|
54
|
+
if foreign_key_was && model_was.respond_to?(:decrement_counter)
|
55
|
+
model_was.decrement_counter(cache_column, foreign_key_was)
|
48
56
|
end
|
49
57
|
end
|
50
58
|
end
|
@@ -62,7 +70,7 @@ module ActiveRecord::Associations::Builder
|
|
62
70
|
klass.attr_readonly cache_column if klass && klass.respond_to?(:attr_readonly)
|
63
71
|
end
|
64
72
|
|
65
|
-
def self.touch_record(o, foreign_key, name, touch) # :nodoc:
|
73
|
+
def self.touch_record(o, foreign_key, name, touch, touch_method) # :nodoc:
|
66
74
|
old_foreign_id = o.changed_attributes[foreign_key]
|
67
75
|
|
68
76
|
if old_foreign_id
|
@@ -77,9 +85,9 @@ module ActiveRecord::Associations::Builder
|
|
77
85
|
|
78
86
|
if old_record
|
79
87
|
if touch != true
|
80
|
-
old_record.
|
88
|
+
old_record.send(touch_method, touch)
|
81
89
|
else
|
82
|
-
old_record.
|
90
|
+
old_record.send(touch_method)
|
83
91
|
end
|
84
92
|
end
|
85
93
|
end
|
@@ -87,9 +95,9 @@ module ActiveRecord::Associations::Builder
|
|
87
95
|
record = o.send name
|
88
96
|
if record && record.persisted?
|
89
97
|
if touch != true
|
90
|
-
record.
|
98
|
+
record.send(touch_method, touch)
|
91
99
|
else
|
92
|
-
record.
|
100
|
+
record.send(touch_method)
|
93
101
|
end
|
94
102
|
end
|
95
103
|
end
|
@@ -100,7 +108,7 @@ module ActiveRecord::Associations::Builder
|
|
100
108
|
touch = reflection.options[:touch]
|
101
109
|
|
102
110
|
callback = lambda { |record|
|
103
|
-
BelongsTo.touch_record(record, foreign_key, n, touch)
|
111
|
+
BelongsTo.touch_record(record, foreign_key, n, touch, belongs_to_touch_method)
|
104
112
|
}
|
105
113
|
|
106
114
|
model.after_save callback, if: :changed?
|
@@ -109,8 +117,25 @@ module ActiveRecord::Associations::Builder
|
|
109
117
|
end
|
110
118
|
|
111
119
|
def self.add_destroy_callbacks(model, reflection)
|
112
|
-
|
113
|
-
|
120
|
+
model.after_destroy lambda { |o| o.association(reflection.name).handle_dependency }
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.define_validations(model, reflection)
|
124
|
+
if reflection.options.key?(:required)
|
125
|
+
reflection.options[:optional] = !reflection.options.delete(:required)
|
126
|
+
end
|
127
|
+
|
128
|
+
if reflection.options[:optional].nil?
|
129
|
+
required = model.belongs_to_required_by_default
|
130
|
+
else
|
131
|
+
required = !reflection.options[:optional]
|
132
|
+
end
|
133
|
+
|
134
|
+
super
|
135
|
+
|
136
|
+
if required
|
137
|
+
model.validates_presence_of reflection.name, message: :required
|
138
|
+
end
|
114
139
|
end
|
115
140
|
end
|
116
141
|
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,9 +68,7 @@ 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
73
|
if scope.arity > 0
|
86
74
|
proc { |owner| instance_exec(owner, &scope).extending(mod) }
|
@@ -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
|
|
@@ -76,6 +76,9 @@ module ActiveRecord::Associations::Builder
|
|
76
76
|
left_model.retrieve_connection
|
77
77
|
end
|
78
78
|
|
79
|
+
def self.primary_key
|
80
|
+
false
|
81
|
+
end
|
79
82
|
}
|
80
83
|
|
81
84
|
join_model.name = "HABTM_#{association_name.to_s.camelize}"
|
@@ -89,13 +92,13 @@ module ActiveRecord::Associations::Builder
|
|
89
92
|
|
90
93
|
def middle_reflection(join_model)
|
91
94
|
middle_name = [lhs_model.name.downcase.pluralize,
|
92
|
-
association_name].join('_').gsub(
|
95
|
+
association_name].join('_'.freeze).gsub('::'.freeze, '_'.freeze).to_sym
|
93
96
|
middle_options = middle_options join_model
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
97
|
+
|
98
|
+
HasMany.create_reflection(lhs_model,
|
99
|
+
middle_name,
|
100
|
+
nil,
|
101
|
+
middle_options)
|
99
102
|
end
|
100
103
|
|
101
104
|
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,11 +1,11 @@
|
|
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
|
8
|
-
valid = super + [:as
|
7
|
+
def self.valid_options(options)
|
8
|
+
valid = super + [:as]
|
9
9
|
valid += [:through, :source, :source_type] if options[:through]
|
10
10
|
valid
|
11
11
|
end
|
@@ -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,9 +1,9 @@
|
|
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
|
6
|
-
super + [:dependent, :primary_key, :inverse_of, :required]
|
5
|
+
def self.valid_options(options)
|
6
|
+
super + [:foreign_type, :dependent, :primary_key, :inverse_of, :required]
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.define_accessors(model, reflection)
|
@@ -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,22 @@ 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
|
-
|
69
|
-
|
70
|
-
|
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
|
+
records = klass.where(reflection.association_primary_key => ids).index_by do |r|
|
76
|
+
r.send(reflection.association_primary_key)
|
77
|
+
end.values_at(*ids)
|
78
|
+
replace(records)
|
79
79
|
end
|
80
80
|
|
81
81
|
def reset
|
@@ -136,6 +136,14 @@ module ActiveRecord
|
|
136
136
|
first_nth_or_last(:forty_two, *args)
|
137
137
|
end
|
138
138
|
|
139
|
+
def third_to_last(*args)
|
140
|
+
first_nth_or_last(:third_to_last, *args)
|
141
|
+
end
|
142
|
+
|
143
|
+
def second_to_last(*args)
|
144
|
+
first_nth_or_last(:second_to_last, *args)
|
145
|
+
end
|
146
|
+
|
139
147
|
def last(*args)
|
140
148
|
first_nth_or_last(:last, *args)
|
141
149
|
end
|
@@ -172,6 +180,7 @@ module ActiveRecord
|
|
172
180
|
# be chained. Since << flattens its argument list and inserts each record,
|
173
181
|
# +push+ and +concat+ behave identically.
|
174
182
|
def concat(*records)
|
183
|
+
records = records.flatten
|
175
184
|
if owner.new_record?
|
176
185
|
load_target
|
177
186
|
concat_records(records)
|
@@ -239,11 +248,7 @@ module ActiveRecord
|
|
239
248
|
|
240
249
|
# Count all records using SQL. Construct options and pass them with
|
241
250
|
# 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
|
-
|
251
|
+
def count(column_name = nil)
|
247
252
|
relation = scope
|
248
253
|
if association_scope.distinct_value
|
249
254
|
# This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
|
@@ -310,7 +315,7 @@ module ActiveRecord
|
|
310
315
|
elsif !loaded? && !association_scope.group_values.empty?
|
311
316
|
load_target.size
|
312
317
|
elsif !loaded? && !association_scope.distinct_value && target.is_a?(Array)
|
313
|
-
unsaved_records = target.select
|
318
|
+
unsaved_records = target.select(&:new_record?)
|
314
319
|
unsaved_records.size + count_records
|
315
320
|
else
|
316
321
|
count_records
|
@@ -343,7 +348,8 @@ module ActiveRecord
|
|
343
348
|
end
|
344
349
|
|
345
350
|
# Returns true if the collections is not empty.
|
346
|
-
#
|
351
|
+
# If block given, loads all records and checks for one or more matches.
|
352
|
+
# Otherwise, equivalent to +!collection.empty?+.
|
347
353
|
def any?
|
348
354
|
if block_given?
|
349
355
|
load_target.any? { |*block_args| yield(*block_args) }
|
@@ -353,7 +359,8 @@ module ActiveRecord
|
|
353
359
|
end
|
354
360
|
|
355
361
|
# Returns true if the collection has more than 1 record.
|
356
|
-
#
|
362
|
+
# If block given, loads all records and checks for two or more matches.
|
363
|
+
# Otherwise, equivalent to +collection.size > 1+.
|
357
364
|
def many?
|
358
365
|
if block_given?
|
359
366
|
load_target.many? { |*block_args| yield(*block_args) }
|
@@ -382,6 +389,8 @@ module ActiveRecord
|
|
382
389
|
replace_common_records_in_memory(other_array, original_target)
|
383
390
|
if other_array != original_target
|
384
391
|
transaction { replace_records(other_array, original_target) }
|
392
|
+
else
|
393
|
+
other_array
|
385
394
|
end
|
386
395
|
end
|
387
396
|
end
|
@@ -416,12 +425,16 @@ module ActiveRecord
|
|
416
425
|
|
417
426
|
def replace_on_target(record, index, skip_callbacks)
|
418
427
|
callback(:before_add, record) unless skip_callbacks
|
428
|
+
|
429
|
+
was_loaded = loaded?
|
419
430
|
yield(record) if block_given?
|
420
431
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
432
|
+
unless !was_loaded && loaded?
|
433
|
+
if index
|
434
|
+
@target[index] = record
|
435
|
+
else
|
436
|
+
@target << record
|
437
|
+
end
|
425
438
|
end
|
426
439
|
|
427
440
|
callback(:after_add, record) unless skip_callbacks
|
@@ -521,7 +534,7 @@ module ActiveRecord
|
|
521
534
|
def delete_or_destroy(records, method)
|
522
535
|
records = records.flatten
|
523
536
|
records.each { |record| raise_on_type_mismatch!(record) }
|
524
|
-
existing_records = records.reject
|
537
|
+
existing_records = records.reject(&:new_record?)
|
525
538
|
|
526
539
|
if existing_records.empty?
|
527
540
|
remove_records(existing_records, records, method)
|
@@ -568,7 +581,7 @@ module ActiveRecord
|
|
568
581
|
def concat_records(records, should_raise = false)
|
569
582
|
result = true
|
570
583
|
|
571
|
-
records.
|
584
|
+
records.each do |record|
|
572
585
|
raise_on_type_mismatch!(record)
|
573
586
|
add_to_target(record) do |rec|
|
574
587
|
result &&= insert_record(rec, true, should_raise) unless owner.new_record?
|
@@ -612,13 +625,8 @@ module ActiveRecord
|
|
612
625
|
if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
613
626
|
assoc = owner.association(reflection.through_reflection.name)
|
614
627
|
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
|
628
|
+
target_reflection = source.send(reflection.source_reflection.name)
|
629
|
+
target_reflection.respond_to?(:include?) ? target_reflection.include?(record) : target_reflection == record
|
622
630
|
} || target.include?(record)
|
623
631
|
else
|
624
632
|
target.include?(record)
|
@@ -629,7 +637,7 @@ module ActiveRecord
|
|
629
637
|
# specified, then #find scans the entire collection.
|
630
638
|
def find_by_scan(*args)
|
631
639
|
expects_array = args.first.kind_of?(Array)
|
632
|
-
ids = args.flatten.compact.map
|
640
|
+
ids = args.flatten.compact.map(&:to_s).uniq
|
633
641
|
|
634
642
|
if ids.size == 1
|
635
643
|
id = ids.first
|