activerecord 4.2.11.3 → 5.0.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1281 -1204
- 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/aggregations.rb +35 -24
- data/lib/active_record/association_relation.rb +3 -3
- 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/join_association.rb +16 -10
- data/lib/active_record/associations/join_dependency.rb +29 -19
- 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/preloader.rb +14 -4
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/associations.rb +317 -209
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +68 -18
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- 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_methods.rb +76 -47
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attribute_set.rb +30 -3
- 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/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/oid.rb +1 -6
- 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/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +363 -133
- 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/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- 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/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/predicate_builder.rb +120 -107
- 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/relation.rb +176 -116
- 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/default.rb +23 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- 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/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.rb +66 -17
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- 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/active_record/validations.rb +33 -32
- data/lib/active_record.rb +8 -4
- 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/migration.rb +7 -0
- 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 +60 -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,10 +1,11 @@
|
|
1
|
-
require 'active_support/core_ext/module/method_transplanting'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
module AttributeMethods
|
5
3
|
module Read
|
6
|
-
|
7
|
-
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
protected
|
8
|
+
|
8
9
|
# We want to generate the methods via module_eval rather than
|
9
10
|
# define_method, because define_method is slower on dispatch.
|
10
11
|
# Evaluating many similar methods may use more memory as the instruction
|
@@ -23,81 +24,52 @@ module ActiveRecord
|
|
23
24
|
# to allocate an object on each call to the attribute method.
|
24
25
|
# Making it frozen means that it doesn't get duped when used to
|
25
26
|
# key the @attributes in read_attribute.
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{const_name}
|
30
|
-
_read_attribute(name) { |n| missing_attribute(n, caller) }
|
31
|
-
end
|
32
|
-
EOMETHOD
|
33
|
-
end
|
34
|
-
}.new
|
35
|
-
|
36
|
-
extend ActiveSupport::Concern
|
37
|
-
|
38
|
-
module ClassMethods
|
39
|
-
[:cache_attributes, :cached_attributes, :cache_attribute?].each do |method_name|
|
40
|
-
define_method method_name do |*|
|
41
|
-
cached_attributes_deprecation_warning(method_name)
|
42
|
-
true
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
protected
|
47
|
-
|
48
|
-
def cached_attributes_deprecation_warning(method_name)
|
49
|
-
ActiveSupport::Deprecation.warn "Calling `#{method_name}` is no longer necessary. All attributes are cached."
|
50
|
-
end
|
51
|
-
|
52
|
-
if Module.methods_transplantable?
|
53
|
-
def define_method_attribute(name)
|
54
|
-
method = ReaderMethodCache[name]
|
55
|
-
generated_attribute_methods.module_eval { define_method name, method }
|
56
|
-
end
|
57
|
-
else
|
58
|
-
def define_method_attribute(name)
|
59
|
-
safe_name = name.unpack('h*').first
|
60
|
-
temp_method = "__temp__#{safe_name}"
|
27
|
+
def define_method_attribute(name)
|
28
|
+
safe_name = name.unpack('h*'.freeze).first
|
29
|
+
temp_method = "__temp__#{safe_name}"
|
61
30
|
|
62
|
-
|
31
|
+
ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
|
63
32
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
69
|
-
STR
|
70
|
-
|
71
|
-
generated_attribute_methods.module_eval do
|
72
|
-
alias_method name, temp_method
|
73
|
-
undef_method temp_method
|
33
|
+
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
34
|
+
def #{temp_method}
|
35
|
+
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
|
36
|
+
_read_attribute(name) { |n| missing_attribute(n, caller) }
|
74
37
|
end
|
38
|
+
STR
|
39
|
+
|
40
|
+
generated_attribute_methods.module_eval do
|
41
|
+
alias_method name, temp_method
|
42
|
+
undef_method temp_method
|
75
43
|
end
|
76
44
|
end
|
77
45
|
end
|
78
46
|
|
79
|
-
ID = 'id'.freeze
|
80
|
-
|
81
47
|
# Returns the value of the attribute identified by <tt>attr_name</tt> after
|
82
48
|
# it has been typecast (for example, "2004-12-12" in a date column is cast
|
83
49
|
# to a date object, like Date.new(2004, 12, 12)).
|
84
50
|
def read_attribute(attr_name, &block)
|
85
51
|
name = attr_name.to_s
|
86
|
-
name = self.class.primary_key if name ==
|
52
|
+
name = self.class.primary_key if name == 'id'.freeze
|
87
53
|
_read_attribute(name, &block)
|
88
54
|
end
|
89
55
|
|
90
56
|
# This method exists to avoid the expensive primary_key check internally, without
|
91
57
|
# breaking compatibility with the read_attribute API
|
92
|
-
|
93
|
-
|
58
|
+
if defined?(JRUBY_VERSION)
|
59
|
+
# This form is significantly faster on JRuby, and this is one of our biggest hotspots.
|
60
|
+
# https://github.com/jruby/jruby/pull/2562
|
61
|
+
def _read_attribute(attr_name, &block) # :nodoc
|
62
|
+
@attributes.fetch_value(attr_name.to_s, &block)
|
63
|
+
end
|
64
|
+
else
|
65
|
+
def _read_attribute(attr_name) # :nodoc:
|
66
|
+
@attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
|
67
|
+
end
|
94
68
|
end
|
95
69
|
|
96
|
-
|
70
|
+
alias :attribute :_read_attribute
|
71
|
+
private :attribute
|
97
72
|
|
98
|
-
def attribute(attribute_name)
|
99
|
-
_read_attribute(attribute_name)
|
100
|
-
end
|
101
73
|
end
|
102
74
|
end
|
103
75
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'active_support/core_ext/string/filters'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
module AttributeMethods
|
5
3
|
module Serialization
|
@@ -11,7 +9,19 @@ module ActiveRecord
|
|
11
9
|
# attribute using this method and it will be handled automatically. The
|
12
10
|
# serialization is done through YAML. If +class_name+ is specified, the
|
13
11
|
# serialized object must be of that class on assignment and retrieval.
|
14
|
-
# Otherwise
|
12
|
+
# Otherwise SerializationTypeMismatch will be raised.
|
13
|
+
#
|
14
|
+
# Empty objects as <tt>{}</tt>, in the case of +Hash+, or <tt>[]</tt>, in the case of
|
15
|
+
# +Array+, will always be persisted as null.
|
16
|
+
#
|
17
|
+
# Keep in mind that database adapters handle certain serialization tasks
|
18
|
+
# for you. For instance: +json+ and +jsonb+ types in PostgreSQL will be
|
19
|
+
# converted between JSON object/array syntax and Ruby +Hash+ or +Array+
|
20
|
+
# objects transparently. There is no need to use #serialize in this
|
21
|
+
# case.
|
22
|
+
#
|
23
|
+
# For more complex cases, such as conversion to or from your application
|
24
|
+
# domain objects, consider using the ActiveRecord::Attributes API.
|
15
25
|
#
|
16
26
|
# ==== Parameters
|
17
27
|
#
|
@@ -51,19 +61,6 @@ module ActiveRecord
|
|
51
61
|
Type::Serialized.new(type, coder)
|
52
62
|
end
|
53
63
|
end
|
54
|
-
|
55
|
-
def serialized_attributes
|
56
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
57
|
-
`serialized_attributes` is deprecated without replacement, and will
|
58
|
-
be removed in Rails 5.0.
|
59
|
-
MSG
|
60
|
-
|
61
|
-
@serialized_attributes ||= Hash[
|
62
|
-
columns.select { |t| t.cast_type.is_a?(Type::Serialized) }.map { |c|
|
63
|
-
[c.name, c.cast_type.coder]
|
64
|
-
}
|
65
|
-
]
|
66
|
-
end
|
67
64
|
end
|
68
65
|
end
|
69
66
|
end
|
@@ -1,32 +1,54 @@
|
|
1
|
+
require 'active_support/core_ext/string/strip'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module AttributeMethods
|
3
5
|
module TimeZoneConversion
|
4
6
|
class TimeZoneConverter < DelegateClass(Type::Value) # :nodoc:
|
5
|
-
|
6
|
-
|
7
|
-
def type_cast_from_database(value)
|
7
|
+
def deserialize(value)
|
8
8
|
convert_time_to_time_zone(super)
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
if value.
|
13
|
-
|
11
|
+
def cast(value)
|
12
|
+
return if value.nil?
|
13
|
+
|
14
|
+
if value.is_a?(Hash)
|
15
|
+
set_time_zone_without_conversion(super)
|
14
16
|
elsif value.respond_to?(:in_time_zone)
|
15
17
|
begin
|
16
|
-
value
|
18
|
+
super(user_input_in_time_zone(value)) || super
|
17
19
|
rescue ArgumentError
|
18
20
|
nil
|
19
21
|
end
|
22
|
+
else
|
23
|
+
map_avoiding_infinite_recursion(super) { |v| cast(v) }
|
20
24
|
end
|
21
25
|
end
|
22
26
|
|
27
|
+
private
|
28
|
+
|
23
29
|
def convert_time_to_time_zone(value)
|
24
|
-
if value.
|
25
|
-
|
26
|
-
|
30
|
+
return if value.nil?
|
31
|
+
|
32
|
+
if value.acts_like?(:time)
|
27
33
|
value.in_time_zone
|
28
|
-
|
34
|
+
elsif value.is_a?(::Float)
|
29
35
|
value
|
36
|
+
else
|
37
|
+
map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_time_zone_without_conversion(value)
|
42
|
+
::Time.zone.local_to_utc(value).in_time_zone
|
43
|
+
end
|
44
|
+
|
45
|
+
def map_avoiding_infinite_recursion(value)
|
46
|
+
map(value) do |v|
|
47
|
+
if value.equal?(v)
|
48
|
+
nil
|
49
|
+
else
|
50
|
+
yield(v)
|
51
|
+
end
|
30
52
|
end
|
31
53
|
end
|
32
54
|
end
|
@@ -39,6 +61,9 @@ module ActiveRecord
|
|
39
61
|
|
40
62
|
class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false
|
41
63
|
self.skip_time_zone_conversion_for_attributes = []
|
64
|
+
|
65
|
+
class_attribute :time_zone_aware_types, instance_writer: false
|
66
|
+
self.time_zone_aware_types = [:datetime, :not_explicitly_configured]
|
42
67
|
end
|
43
68
|
|
44
69
|
module ClassMethods
|
@@ -59,9 +84,31 @@ module ActiveRecord
|
|
59
84
|
end
|
60
85
|
|
61
86
|
def create_time_zone_conversion_attribute?(name, cast_type)
|
62
|
-
time_zone_aware_attributes &&
|
63
|
-
!self.skip_time_zone_conversion_for_attributes.include?(name.to_sym)
|
64
|
-
|
87
|
+
enabled_for_column = time_zone_aware_attributes &&
|
88
|
+
!self.skip_time_zone_conversion_for_attributes.include?(name.to_sym)
|
89
|
+
result = enabled_for_column &&
|
90
|
+
time_zone_aware_types.include?(cast_type.type)
|
91
|
+
|
92
|
+
if enabled_for_column &&
|
93
|
+
!result &&
|
94
|
+
cast_type.type == :time &&
|
95
|
+
time_zone_aware_types.include?(:not_explicitly_configured)
|
96
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
|
97
|
+
Time columns will become time zone aware in Rails 5.1. This
|
98
|
+
still causes `String`s to be parsed as if they were in `Time.zone`,
|
99
|
+
and `Time`s to be converted to `Time.zone`.
|
100
|
+
|
101
|
+
To keep the old behavior, you must add the following to your initializer:
|
102
|
+
|
103
|
+
config.active_record.time_zone_aware_types = [:datetime]
|
104
|
+
|
105
|
+
To silence this deprecation warning, add the following:
|
106
|
+
|
107
|
+
config.active_record.time_zone_aware_types = [:datetime, :time]
|
108
|
+
MESSAGE
|
109
|
+
end
|
110
|
+
|
111
|
+
result
|
65
112
|
end
|
66
113
|
end
|
67
114
|
end
|
@@ -1,21 +1,6 @@
|
|
1
|
-
require 'active_support/core_ext/module/method_transplanting'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
module AttributeMethods
|
5
3
|
module Write
|
6
|
-
WriterMethodCache = Class.new(AttributeMethodCache) {
|
7
|
-
private
|
8
|
-
|
9
|
-
def method_body(method_name, const_name)
|
10
|
-
<<-EOMETHOD
|
11
|
-
def #{method_name}(value)
|
12
|
-
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{const_name}
|
13
|
-
write_attribute(name, value)
|
14
|
-
end
|
15
|
-
EOMETHOD
|
16
|
-
end
|
17
|
-
}.new
|
18
|
-
|
19
4
|
extend ActiveSupport::Concern
|
20
5
|
|
21
6
|
included do
|
@@ -25,27 +10,18 @@ module ActiveRecord
|
|
25
10
|
module ClassMethods
|
26
11
|
protected
|
27
12
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
}
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
41
|
-
def __temp__#{safe_name}=(value)
|
42
|
-
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
|
43
|
-
write_attribute(name, value)
|
44
|
-
end
|
45
|
-
alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
|
46
|
-
undef_method :__temp__#{safe_name}=
|
47
|
-
STR
|
48
|
-
end
|
13
|
+
def define_method_attribute=(name)
|
14
|
+
safe_name = name.unpack('h*'.freeze).first
|
15
|
+
ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
|
16
|
+
|
17
|
+
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
18
|
+
def __temp__#{safe_name}=(value)
|
19
|
+
name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
|
20
|
+
write_attribute(name, value)
|
21
|
+
end
|
22
|
+
alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
|
23
|
+
undef_method :__temp__#{safe_name}=
|
24
|
+
STR
|
49
25
|
end
|
50
26
|
end
|
51
27
|
|
@@ -56,7 +32,7 @@ module ActiveRecord
|
|
56
32
|
write_attribute_with_type_cast(attr_name, value, true)
|
57
33
|
end
|
58
34
|
|
59
|
-
def raw_write_attribute(attr_name, value)
|
35
|
+
def raw_write_attribute(attr_name, value) # :nodoc:
|
60
36
|
write_attribute_with_type_cast(attr_name, value, false)
|
61
37
|
end
|
62
38
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'active_support/core_ext/enumerable'
|
2
2
|
require 'active_support/core_ext/string/filters'
|
3
3
|
require 'mutex_m'
|
4
|
-
require '
|
4
|
+
require 'concurrent/map'
|
5
5
|
|
6
6
|
module ActiveRecord
|
7
7
|
# = Active Record Attribute Methods
|
@@ -34,30 +34,6 @@ module ActiveRecord
|
|
34
34
|
|
35
35
|
BLACKLISTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
|
36
36
|
|
37
|
-
class AttributeMethodCache
|
38
|
-
def initialize
|
39
|
-
@module = Module.new
|
40
|
-
@method_cache = ThreadSafe::Cache.new
|
41
|
-
end
|
42
|
-
|
43
|
-
def [](name)
|
44
|
-
@method_cache.compute_if_absent(name) do
|
45
|
-
safe_name = name.unpack('h*').first
|
46
|
-
temp_method = "__temp__#{safe_name}"
|
47
|
-
ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
|
48
|
-
@module.module_eval method_body(temp_method, safe_name), __FILE__, __LINE__
|
49
|
-
@module.instance_method temp_method
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
# Override this method in the subclasses for method body.
|
56
|
-
def method_body(method_name, const_name)
|
57
|
-
raise NotImplementedError, "Subclasses must implement a method_body(method_name, const_name) method."
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
37
|
class GeneratedAttributeMethods < Module; end # :nodoc:
|
62
38
|
|
63
39
|
module ClassMethods
|
@@ -83,7 +59,7 @@ module ActiveRecord
|
|
83
59
|
generated_attribute_methods.synchronize do
|
84
60
|
return false if @attribute_methods_generated
|
85
61
|
superclass.define_attribute_methods unless self == base_class
|
86
|
-
super(
|
62
|
+
super(attribute_names)
|
87
63
|
@attribute_methods_generated = true
|
88
64
|
end
|
89
65
|
true
|
@@ -96,7 +72,7 @@ module ActiveRecord
|
|
96
72
|
end
|
97
73
|
end
|
98
74
|
|
99
|
-
# Raises
|
75
|
+
# Raises an ActiveRecord::DangerousAttributeError exception when an
|
100
76
|
# \Active \Record method is defined in the model, otherwise +false+.
|
101
77
|
#
|
102
78
|
# class Person < ActiveRecord::Base
|
@@ -106,7 +82,7 @@ module ActiveRecord
|
|
106
82
|
# end
|
107
83
|
#
|
108
84
|
# Person.instance_method_already_implemented?(:save)
|
109
|
-
# # => ActiveRecord::DangerousAttributeError: save is defined by
|
85
|
+
# # => ActiveRecord::DangerousAttributeError: save is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name.
|
110
86
|
#
|
111
87
|
# Person.instance_method_already_implemented?(:name)
|
112
88
|
# # => false
|
@@ -150,7 +126,7 @@ module ActiveRecord
|
|
150
126
|
BLACKLISTED_CLASS_METHODS.include?(method_name.to_s) || class_method_defined_within?(method_name, Base)
|
151
127
|
end
|
152
128
|
|
153
|
-
def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc
|
129
|
+
def class_method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
|
154
130
|
if klass.respond_to?(name, true)
|
155
131
|
if superklass.respond_to?(name, true)
|
156
132
|
klass.method(name).owner != superklass.method(name).owner
|
@@ -185,14 +161,27 @@ module ActiveRecord
|
|
185
161
|
# # => ["id", "created_at", "updated_at", "name", "age"]
|
186
162
|
def attribute_names
|
187
163
|
@attribute_names ||= if !abstract_class? && table_exists?
|
188
|
-
|
164
|
+
attribute_types.keys
|
189
165
|
else
|
190
166
|
[]
|
191
167
|
end
|
192
168
|
end
|
193
169
|
|
170
|
+
# Returns true if the given attribute exists, otherwise false.
|
171
|
+
#
|
172
|
+
# class Person < ActiveRecord::Base
|
173
|
+
# end
|
174
|
+
#
|
175
|
+
# Person.has_attribute?('name') # => true
|
176
|
+
# Person.has_attribute?(:age) # => true
|
177
|
+
# Person.has_attribute?(:nothing) # => false
|
178
|
+
def has_attribute?(attr_name)
|
179
|
+
attribute_types.key?(attr_name.to_s)
|
180
|
+
end
|
181
|
+
|
194
182
|
# Returns the column object for the named attribute.
|
195
|
-
# Returns
|
183
|
+
# Returns a +ActiveRecord::ConnectionAdapters::NullColumn+ if the
|
184
|
+
# named attribute does not exist.
|
196
185
|
#
|
197
186
|
# class Person < ActiveRecord::Base
|
198
187
|
# end
|
@@ -202,23 +191,18 @@ module ActiveRecord
|
|
202
191
|
# # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
|
203
192
|
#
|
204
193
|
# person.column_for_attribute(:nothing)
|
205
|
-
# # => nil
|
194
|
+
# # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
|
206
195
|
def column_for_attribute(name)
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
`#column_for_attribute` will return a null object for non-existent
|
211
|
-
columns in Rails 5. Use `#has_attribute?` if you need to check for
|
212
|
-
an attribute's existence.
|
213
|
-
MSG
|
196
|
+
name = name.to_s
|
197
|
+
columns_hash.fetch(name) do
|
198
|
+
ConnectionAdapters::NullColumn.new(name)
|
214
199
|
end
|
215
|
-
column
|
216
200
|
end
|
217
201
|
end
|
218
202
|
|
219
203
|
# A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
|
220
204
|
# <tt>person.respond_to?(:name=)</tt>, and <tt>person.respond_to?(:name?)</tt>
|
221
|
-
# which will all return +true+. It also
|
205
|
+
# which will all return +true+. It also defines the attribute methods if they have
|
222
206
|
# not been generated.
|
223
207
|
#
|
224
208
|
# class Person < ActiveRecord::Base
|
@@ -234,7 +218,15 @@ module ActiveRecord
|
|
234
218
|
# person.respond_to(:nothing) # => false
|
235
219
|
def respond_to?(name, include_private = false)
|
236
220
|
return false unless super
|
237
|
-
|
221
|
+
|
222
|
+
case name
|
223
|
+
when :to_partial_path
|
224
|
+
name = "to_partial_path".freeze
|
225
|
+
when :to_model
|
226
|
+
name = "to_model".freeze
|
227
|
+
else
|
228
|
+
name = name.to_s
|
229
|
+
end
|
238
230
|
|
239
231
|
# If the result is true then check for the select case.
|
240
232
|
# For queries selecting a subset of columns, return false for unselected columns.
|
@@ -287,8 +279,9 @@ module ActiveRecord
|
|
287
279
|
# Returns an <tt>#inspect</tt>-like string for the value of the
|
288
280
|
# attribute +attr_name+. String attributes are truncated up to 50
|
289
281
|
# characters, Date and Time attributes are returned in the
|
290
|
-
# <tt>:db</tt> format
|
291
|
-
# <tt>#inspect</tt> without
|
282
|
+
# <tt>:db</tt> format, Array attributes are truncated up to 10 values.
|
283
|
+
# Other attributes return the value of <tt>#inspect</tt> without
|
284
|
+
# modification.
|
292
285
|
#
|
293
286
|
# person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
|
294
287
|
#
|
@@ -299,7 +292,7 @@ module ActiveRecord
|
|
299
292
|
# # => "\"2012-10-22 00:15:07\""
|
300
293
|
#
|
301
294
|
# person.attribute_for_inspect(:tag_ids)
|
302
|
-
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
295
|
+
# # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ...]"
|
303
296
|
def attribute_for_inspect(attr_name)
|
304
297
|
value = read_attribute(attr_name)
|
305
298
|
|
@@ -307,6 +300,9 @@ module ActiveRecord
|
|
307
300
|
"#{value[0, 50]}...".inspect
|
308
301
|
elsif value.is_a?(Date) || value.is_a?(Time)
|
309
302
|
%("#{value.to_s(:db)}")
|
303
|
+
elsif value.is_a?(Array) && value.size > 10
|
304
|
+
inspected = value.first(10).inspect
|
305
|
+
%(#{inspected[0...-1]}, ...])
|
310
306
|
else
|
311
307
|
value.inspect
|
312
308
|
end
|
@@ -338,7 +334,7 @@ module ActiveRecord
|
|
338
334
|
#
|
339
335
|
# Note: +:id+ is always present.
|
340
336
|
#
|
341
|
-
# Alias for the
|
337
|
+
# Alias for the #read_attribute method.
|
342
338
|
#
|
343
339
|
# class Person < ActiveRecord::Base
|
344
340
|
# belongs_to :organization
|
@@ -356,7 +352,7 @@ module ActiveRecord
|
|
356
352
|
end
|
357
353
|
|
358
354
|
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
|
359
|
-
# (Alias for the protected
|
355
|
+
# (Alias for the protected #write_attribute method).
|
360
356
|
#
|
361
357
|
# class Person < ActiveRecord::Base
|
362
358
|
# end
|
@@ -369,6 +365,39 @@ module ActiveRecord
|
|
369
365
|
write_attribute(attr_name, value)
|
370
366
|
end
|
371
367
|
|
368
|
+
# Returns the name of all database fields which have been read from this
|
369
|
+
# model. This can be useful in development mode to determine which fields
|
370
|
+
# need to be selected. For performance critical pages, selecting only the
|
371
|
+
# required fields can be an easy performance win (assuming you aren't using
|
372
|
+
# all of the fields on the model).
|
373
|
+
#
|
374
|
+
# For example:
|
375
|
+
#
|
376
|
+
# class PostsController < ActionController::Base
|
377
|
+
# after_action :print_accessed_fields, only: :index
|
378
|
+
#
|
379
|
+
# def index
|
380
|
+
# @posts = Post.all
|
381
|
+
# end
|
382
|
+
#
|
383
|
+
# private
|
384
|
+
#
|
385
|
+
# def print_accessed_fields
|
386
|
+
# p @posts.first.accessed_fields
|
387
|
+
# end
|
388
|
+
# end
|
389
|
+
#
|
390
|
+
# Which allows you to quickly change your code to:
|
391
|
+
#
|
392
|
+
# class PostsController < ActionController::Base
|
393
|
+
# def index
|
394
|
+
# @posts = Post.select(:id, :title, :author_id, :updated_at)
|
395
|
+
# end
|
396
|
+
# end
|
397
|
+
def accessed_fields
|
398
|
+
@attributes.accessed
|
399
|
+
end
|
400
|
+
|
372
401
|
protected
|
373
402
|
|
374
403
|
def clone_attribute_value(reader_method, attribute_name) # :nodoc:
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class AttributeMutationTracker # :nodoc:
|
3
|
+
def initialize(attributes)
|
4
|
+
@attributes = attributes
|
5
|
+
end
|
6
|
+
|
7
|
+
def changed_values
|
8
|
+
attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
|
9
|
+
if changed?(attr_name)
|
10
|
+
result[attr_name] = attributes[attr_name].original_value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def changes
|
16
|
+
attr_names.each_with_object({}.with_indifferent_access) do |attr_name, result|
|
17
|
+
if changed?(attr_name)
|
18
|
+
result[attr_name] = [attributes[attr_name].original_value, attributes.fetch_value(attr_name)]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def changed?(attr_name)
|
24
|
+
attr_name = attr_name.to_s
|
25
|
+
attributes[attr_name].changed?
|
26
|
+
end
|
27
|
+
|
28
|
+
def changed_in_place?(attr_name)
|
29
|
+
attributes[attr_name].changed_in_place?
|
30
|
+
end
|
31
|
+
|
32
|
+
def forget_change(attr_name)
|
33
|
+
attr_name = attr_name.to_s
|
34
|
+
attributes[attr_name] = attributes[attr_name].forgetting_assignment
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
attr_reader :attributes
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def attr_names
|
44
|
+
attributes.keys
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class NullMutationTracker # :nodoc:
|
49
|
+
include Singleton
|
50
|
+
|
51
|
+
def changed_values
|
52
|
+
{}
|
53
|
+
end
|
54
|
+
|
55
|
+
def changes
|
56
|
+
{}
|
57
|
+
end
|
58
|
+
|
59
|
+
def changed?(*)
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def changed_in_place?(*)
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def forget_change(*)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
22
22
|
end
|
23
23
|
|
24
24
|
class LazyAttributeHash # :nodoc:
|
25
|
-
delegate :transform_values, to: :materialize
|
25
|
+
delegate :transform_values, :each_key, to: :materialize
|
26
26
|
|
27
27
|
def initialize(types, values, additional_types)
|
28
28
|
@types = types
|
@@ -47,12 +47,14 @@ module ActiveRecord
|
|
47
47
|
delegate_hash[key] = value
|
48
48
|
end
|
49
49
|
|
50
|
-
def
|
51
|
-
|
50
|
+
def deep_dup
|
51
|
+
dup.tap do |copy|
|
52
|
+
copy.instance_variable_set(:@delegate_hash, delegate_hash.transform_values(&:dup))
|
53
|
+
end
|
52
54
|
end
|
53
55
|
|
54
56
|
def initialize_dup(_)
|
55
|
-
@delegate_hash = delegate_hash
|
57
|
+
@delegate_hash = Hash[delegate_hash]
|
56
58
|
super
|
57
59
|
end
|
58
60
|
|