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
@@ -3,36 +3,53 @@ module ActiveRecord
|
|
3
3
|
class StatementPool
|
4
4
|
include Enumerable
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
@
|
8
|
-
@max
|
6
|
+
def initialize(max = 1000)
|
7
|
+
@cache = Hash.new { |h,pid| h[pid] = {} }
|
8
|
+
@max = max
|
9
9
|
end
|
10
10
|
|
11
|
-
def each
|
12
|
-
|
11
|
+
def each(&block)
|
12
|
+
cache.each(&block)
|
13
13
|
end
|
14
14
|
|
15
15
|
def key?(key)
|
16
|
-
|
16
|
+
cache.key?(key)
|
17
17
|
end
|
18
18
|
|
19
19
|
def [](key)
|
20
|
-
|
20
|
+
cache[key]
|
21
21
|
end
|
22
22
|
|
23
23
|
def length
|
24
|
-
|
24
|
+
cache.length
|
25
25
|
end
|
26
26
|
|
27
|
-
def []=(sql,
|
28
|
-
|
27
|
+
def []=(sql, stmt)
|
28
|
+
while @max <= cache.size
|
29
|
+
dealloc(cache.shift.last)
|
30
|
+
end
|
31
|
+
cache[sql] = stmt
|
29
32
|
end
|
30
33
|
|
31
34
|
def clear
|
32
|
-
|
35
|
+
cache.each_value do |stmt|
|
36
|
+
dealloc stmt
|
37
|
+
end
|
38
|
+
cache.clear
|
33
39
|
end
|
34
40
|
|
35
41
|
def delete(key)
|
42
|
+
dealloc cache[key]
|
43
|
+
cache.delete(key)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def cache
|
49
|
+
@cache[Process.pid]
|
50
|
+
end
|
51
|
+
|
52
|
+
def dealloc(stmt)
|
36
53
|
raise NotImplementedError
|
37
54
|
end
|
38
55
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
|
6
6
|
# Establishes the connection to the database. Accepts a hash as input where
|
7
7
|
# the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
|
8
|
-
# example for regular databases (MySQL,
|
8
|
+
# example for regular databases (MySQL, PostgreSQL, etc):
|
9
9
|
#
|
10
10
|
# ActiveRecord::Base.establish_connection(
|
11
11
|
# adapter: "mysql",
|
@@ -35,14 +35,14 @@ module ActiveRecord
|
|
35
35
|
# "postgres://myuser:mypass@localhost/somedatabase"
|
36
36
|
# )
|
37
37
|
#
|
38
|
-
# In case
|
39
|
-
# automatically loads the contents of config/database.yml into it),
|
38
|
+
# In case {ActiveRecord::Base.configurations}[rdoc-ref:Core.configurations]
|
39
|
+
# is set (Rails automatically loads the contents of config/database.yml into it),
|
40
40
|
# a symbol can also be given as argument, representing a key in the
|
41
41
|
# configuration hash:
|
42
42
|
#
|
43
43
|
# ActiveRecord::Base.establish_connection(:production)
|
44
44
|
#
|
45
|
-
# The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
|
45
|
+
# The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
|
46
46
|
# may be returned on an error.
|
47
47
|
def establish_connection(spec = nil)
|
48
48
|
spec ||= DEFAULT_ENV.call.to_sym
|
@@ -88,7 +88,7 @@ module ActiveRecord
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def connection_id
|
91
|
-
ActiveRecord::RuntimeRegistry.connection_id
|
91
|
+
ActiveRecord::RuntimeRegistry.connection_id ||= Thread.current.object_id
|
92
92
|
end
|
93
93
|
|
94
94
|
def connection_id=(connection_id)
|
data/lib/active_record/core.rb
CHANGED
@@ -85,17 +85,30 @@ module ActiveRecord
|
|
85
85
|
mattr_accessor :dump_schema_after_migration, instance_writer: false
|
86
86
|
self.dump_schema_after_migration = true
|
87
87
|
|
88
|
+
##
|
89
|
+
# :singleton-method:
|
90
|
+
# Specifies which database schemas to dump when calling db:structure:dump.
|
91
|
+
# If the value is :schema_search_path (the default), any schemas listed in
|
92
|
+
# schema_search_path are dumped. Use :all to dump all schemas regardless
|
93
|
+
# of schema_search_path, or a string of comma separated schemas for a
|
94
|
+
# custom list.
|
95
|
+
mattr_accessor :dump_schemas, instance_writer: false
|
96
|
+
self.dump_schemas = :schema_search_path
|
97
|
+
|
98
|
+
##
|
99
|
+
# :singleton-method:
|
100
|
+
# Specify a threshold for the size of query result sets. If the number of
|
101
|
+
# records in the set exceeds the threshold, a warning is logged. This can
|
102
|
+
# be used to identify queries which load thousands of records and
|
103
|
+
# potentially cause memory bloat.
|
104
|
+
mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
|
105
|
+
self.warn_on_records_fetched_greater_than = nil
|
106
|
+
|
88
107
|
mattr_accessor :maintain_test_schema, instance_accessor: false
|
89
108
|
|
90
|
-
|
91
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
92
|
-
Implicit join references were removed with Rails 4.1.
|
93
|
-
Make sure to remove this configuration because it does nothing.
|
94
|
-
MSG
|
95
|
-
end
|
109
|
+
mattr_accessor :belongs_to_required_by_default, instance_accessor: false
|
96
110
|
|
97
111
|
class_attribute :default_connection_handler, instance_writer: false
|
98
|
-
class_attribute :find_by_statement_cache
|
99
112
|
|
100
113
|
def self.connection_handler
|
101
114
|
ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
|
@@ -115,10 +128,11 @@ module ActiveRecord
|
|
115
128
|
end
|
116
129
|
|
117
130
|
def initialize_find_by_cache # :nodoc:
|
118
|
-
|
131
|
+
@find_by_statement_cache = {}.extend(Mutex_m)
|
119
132
|
end
|
120
133
|
|
121
134
|
def inherited(child_class) # :nodoc:
|
135
|
+
# initialize cache at class definition for thread safety
|
122
136
|
child_class.initialize_find_by_cache
|
123
137
|
super
|
124
138
|
end
|
@@ -126,12 +140,9 @@ module ActiveRecord
|
|
126
140
|
def find(*ids) # :nodoc:
|
127
141
|
# We don't have cache keys for this stuff yet
|
128
142
|
return super unless ids.length == 1
|
129
|
-
# Allow symbols to super to maintain compatibility for deprecated finders until Rails 5
|
130
|
-
return super if ids.first.kind_of?(Symbol)
|
131
143
|
return super if block_given? ||
|
132
144
|
primary_key.nil? ||
|
133
|
-
|
134
|
-
current_scope ||
|
145
|
+
scope_attributes? ||
|
135
146
|
columns_hash.include?(inheritance_column) ||
|
136
147
|
ids.first.kind_of?(Array)
|
137
148
|
|
@@ -143,57 +154,54 @@ module ActiveRecord
|
|
143
154
|
Please pass the id of the object by calling `.id`
|
144
155
|
MSG
|
145
156
|
end
|
157
|
+
|
146
158
|
key = primary_key
|
147
159
|
|
148
|
-
|
149
|
-
|
150
|
-
where(key => params.bind).limit(1)
|
151
|
-
}
|
160
|
+
statement = cached_find_by_statement(key) { |params|
|
161
|
+
where(key => params.bind).limit(1)
|
152
162
|
}
|
153
|
-
record =
|
163
|
+
record = statement.execute([id], self, connection).first
|
154
164
|
unless record
|
155
|
-
raise RecordNotFound
|
165
|
+
raise RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}",
|
166
|
+
name, primary_key, id)
|
156
167
|
end
|
157
168
|
record
|
158
169
|
rescue RangeError
|
159
|
-
raise RecordNotFound
|
170
|
+
raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
|
171
|
+
name, primary_key)
|
160
172
|
end
|
161
173
|
|
162
174
|
def find_by(*args) # :nodoc:
|
163
|
-
return super if
|
164
|
-
return super if default_scopes.any?
|
175
|
+
return super if scope_attributes? || !(Hash === args.first) || reflect_on_all_aggregations.any?
|
165
176
|
|
166
177
|
hash = args.first
|
167
178
|
|
168
179
|
return super if hash.values.any? { |v|
|
169
|
-
v.nil? || Array === v || Hash === v
|
180
|
+
v.nil? || Array === v || Hash === v || Relation === v
|
170
181
|
}
|
171
182
|
|
172
183
|
# We can't cache Post.find_by(author: david) ...yet
|
173
184
|
return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
|
174
185
|
|
175
|
-
|
186
|
+
keys = hash.keys
|
176
187
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
wheres = key.each_with_object({}) { |param,o|
|
181
|
-
o[param] = params.bind
|
182
|
-
}
|
183
|
-
klass.where(wheres).limit(1)
|
188
|
+
statement = cached_find_by_statement(keys) { |params|
|
189
|
+
wheres = keys.each_with_object({}) { |param, o|
|
190
|
+
o[param] = params.bind
|
184
191
|
}
|
192
|
+
where(wheres).limit(1)
|
185
193
|
}
|
186
194
|
begin
|
187
|
-
|
188
|
-
rescue TypeError
|
189
|
-
raise ActiveRecord::StatementInvalid
|
195
|
+
statement.execute(hash.values, self, connection).first
|
196
|
+
rescue TypeError
|
197
|
+
raise ActiveRecord::StatementInvalid
|
190
198
|
rescue RangeError
|
191
199
|
nil
|
192
200
|
end
|
193
201
|
end
|
194
202
|
|
195
203
|
def find_by!(*args) # :nodoc:
|
196
|
-
find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}")
|
204
|
+
find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}", name)
|
197
205
|
end
|
198
206
|
|
199
207
|
def initialize_generated_modules # :nodoc:
|
@@ -217,7 +225,7 @@ module ActiveRecord
|
|
217
225
|
elsif !connected?
|
218
226
|
"#{super} (call '#{super}.connection' to establish a connection)"
|
219
227
|
elsif table_exists?
|
220
|
-
attr_list =
|
228
|
+
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ', '
|
221
229
|
"#{super}(#{attr_list})"
|
222
230
|
else
|
223
231
|
"#{super}(Table doesn't exist)"
|
@@ -235,7 +243,7 @@ module ActiveRecord
|
|
235
243
|
# scope :published_and_commented, -> { published.and(self.arel_table[:comments_count].gt(0)) }
|
236
244
|
# end
|
237
245
|
def arel_table # :nodoc:
|
238
|
-
@arel_table ||= Arel::Table.new(table_name,
|
246
|
+
@arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
|
239
247
|
end
|
240
248
|
|
241
249
|
# Returns the Arel engine.
|
@@ -248,10 +256,24 @@ module ActiveRecord
|
|
248
256
|
end
|
249
257
|
end
|
250
258
|
|
259
|
+
def predicate_builder # :nodoc:
|
260
|
+
@predicate_builder ||= PredicateBuilder.new(table_metadata)
|
261
|
+
end
|
262
|
+
|
263
|
+
def type_caster # :nodoc:
|
264
|
+
TypeCaster::Map.new(self)
|
265
|
+
end
|
266
|
+
|
251
267
|
private
|
252
268
|
|
253
|
-
def
|
254
|
-
|
269
|
+
def cached_find_by_statement(key, &block) # :nodoc:
|
270
|
+
@find_by_statement_cache[key] || @find_by_statement_cache.synchronize {
|
271
|
+
@find_by_statement_cache[key] ||= StatementCache.create(connection, &block)
|
272
|
+
}
|
273
|
+
end
|
274
|
+
|
275
|
+
def relation # :nodoc:
|
276
|
+
relation = Relation.create(self, arel_table, predicate_builder)
|
255
277
|
|
256
278
|
if finder_needs_type_condition?
|
257
279
|
relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
|
@@ -259,6 +281,10 @@ module ActiveRecord
|
|
259
281
|
relation
|
260
282
|
end
|
261
283
|
end
|
284
|
+
|
285
|
+
def table_metadata # :nodoc:
|
286
|
+
TableMetadata.new(self, arel_table)
|
287
|
+
end
|
262
288
|
end
|
263
289
|
|
264
290
|
# New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
|
@@ -269,16 +295,14 @@ module ActiveRecord
|
|
269
295
|
# ==== Example:
|
270
296
|
# # Instantiates a single new object
|
271
297
|
# User.new(first_name: 'Jamie')
|
272
|
-
def initialize(attributes = nil
|
273
|
-
@attributes = self.class._default_attributes.
|
298
|
+
def initialize(attributes = nil)
|
299
|
+
@attributes = self.class._default_attributes.deep_dup
|
274
300
|
self.class.define_attribute_methods
|
275
301
|
|
276
302
|
init_internals
|
277
303
|
initialize_internals_callback
|
278
304
|
|
279
|
-
|
280
|
-
# Remove it when we drop support to this gem.
|
281
|
-
init_attributes(attributes, options) if attributes
|
305
|
+
assign_attributes(attributes) if attributes
|
282
306
|
|
283
307
|
yield self if block_given?
|
284
308
|
_run_initialize_callbacks
|
@@ -286,7 +310,7 @@ module ActiveRecord
|
|
286
310
|
|
287
311
|
# Initialize an empty model object from +coder+. +coder+ should be
|
288
312
|
# the result of previously encoding an Active Record model, using
|
289
|
-
#
|
313
|
+
# #encode_with.
|
290
314
|
#
|
291
315
|
# class Post < ActiveRecord::Base
|
292
316
|
# end
|
@@ -342,14 +366,11 @@ module ActiveRecord
|
|
342
366
|
|
343
367
|
##
|
344
368
|
def initialize_dup(other) # :nodoc:
|
345
|
-
@attributes = @attributes.
|
369
|
+
@attributes = @attributes.deep_dup
|
346
370
|
@attributes.reset(self.class.primary_key)
|
347
371
|
|
348
372
|
_run_initialize_callbacks
|
349
373
|
|
350
|
-
@aggregation_cache = {}
|
351
|
-
@association_cache = {}
|
352
|
-
|
353
374
|
@new_record = true
|
354
375
|
@destroyed = false
|
355
376
|
|
@@ -358,7 +379,7 @@ module ActiveRecord
|
|
358
379
|
|
359
380
|
# Populate +coder+ with attributes about this record that should be
|
360
381
|
# serialized. The structure of +coder+ defined in this method is
|
361
|
-
# guaranteed to match the structure of +coder+ passed to the
|
382
|
+
# guaranteed to match the structure of +coder+ passed to the #init_with
|
362
383
|
# method.
|
363
384
|
#
|
364
385
|
# Example:
|
@@ -373,7 +394,7 @@ module ActiveRecord
|
|
373
394
|
coder['raw_attributes'] = attributes_before_type_cast
|
374
395
|
coder['attributes'] = @attributes
|
375
396
|
coder['new_record'] = new_record?
|
376
|
-
coder['active_record_yaml_version'] =
|
397
|
+
coder['active_record_yaml_version'] = 1
|
377
398
|
end
|
378
399
|
|
379
400
|
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
@@ -456,7 +477,7 @@ module ActiveRecord
|
|
456
477
|
"#<#{self.class} #{inspection}>"
|
457
478
|
end
|
458
479
|
|
459
|
-
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from
|
480
|
+
# Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
|
460
481
|
# when pp is required.
|
461
482
|
def pretty_print(pp)
|
462
483
|
return super if custom_inspect_method_defined?
|
@@ -487,51 +508,6 @@ module ActiveRecord
|
|
487
508
|
|
488
509
|
private
|
489
510
|
|
490
|
-
def set_transaction_state(state) # :nodoc:
|
491
|
-
@transaction_state = state
|
492
|
-
end
|
493
|
-
|
494
|
-
def has_transactional_callbacks? # :nodoc:
|
495
|
-
!_rollback_callbacks.empty? || !_commit_callbacks.empty?
|
496
|
-
end
|
497
|
-
|
498
|
-
# Updates the attributes on this particular ActiveRecord object so that
|
499
|
-
# if it is associated with a transaction, then the state of the AR object
|
500
|
-
# will be updated to reflect the current state of the transaction
|
501
|
-
#
|
502
|
-
# The @transaction_state variable stores the states of the associated
|
503
|
-
# transaction. This relies on the fact that a transaction can only be in
|
504
|
-
# one rollback or commit (otherwise a list of states would be required)
|
505
|
-
# Each AR object inside of a transaction carries that transaction's
|
506
|
-
# TransactionState.
|
507
|
-
#
|
508
|
-
# This method checks to see if the ActiveRecord object's state reflects
|
509
|
-
# the TransactionState, and rolls back or commits the ActiveRecord object
|
510
|
-
# as appropriate.
|
511
|
-
#
|
512
|
-
# Since ActiveRecord objects can be inside multiple transactions, this
|
513
|
-
# method recursively goes through the parent of the TransactionState and
|
514
|
-
# checks if the ActiveRecord object reflects the state of the object.
|
515
|
-
def sync_with_transaction_state
|
516
|
-
update_attributes_from_transaction_state(@transaction_state, 0)
|
517
|
-
end
|
518
|
-
|
519
|
-
def update_attributes_from_transaction_state(transaction_state, depth)
|
520
|
-
@reflects_state = [false] if depth == 0
|
521
|
-
|
522
|
-
if transaction_state && transaction_state.finalized? && !has_transactional_callbacks?
|
523
|
-
unless @reflects_state[depth]
|
524
|
-
restore_transaction_record_state if transaction_state.rolledback?
|
525
|
-
clear_transaction_record_state
|
526
|
-
@reflects_state[depth] = true
|
527
|
-
end
|
528
|
-
|
529
|
-
if transaction_state.parent && !@reflects_state[depth+1]
|
530
|
-
update_attributes_from_transaction_state(transaction_state.parent, depth+1)
|
531
|
-
end
|
532
|
-
end
|
533
|
-
end
|
534
|
-
|
535
511
|
# Under Ruby 1.9, Array#flatten will call #to_ary (recursively) on each of the elements
|
536
512
|
# of the array, and then rescues from the possible NoMethodError. If those elements are
|
537
513
|
# ActiveRecord::Base's, then this triggers the various method_missing's that we have,
|
@@ -545,8 +521,6 @@ module ActiveRecord
|
|
545
521
|
end
|
546
522
|
|
547
523
|
def init_internals
|
548
|
-
@aggregation_cache = {}
|
549
|
-
@association_cache = {}
|
550
524
|
@readonly = false
|
551
525
|
@destroyed = false
|
552
526
|
@marked_for_destruction = false
|
@@ -560,12 +534,6 @@ module ActiveRecord
|
|
560
534
|
def initialize_internals_callback
|
561
535
|
end
|
562
536
|
|
563
|
-
# This method is needed to make protected_attributes gem easier to hook.
|
564
|
-
# Remove it when we drop support to this gem.
|
565
|
-
def init_attributes(attributes, options)
|
566
|
-
assign_attributes(attributes)
|
567
|
-
end
|
568
|
-
|
569
537
|
def thaw
|
570
538
|
if frozen?
|
571
539
|
@attributes = @attributes.dup
|
@@ -37,23 +37,22 @@ module ActiveRecord
|
|
37
37
|
reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
|
38
38
|
counter_name = reflection.counter_cache_column
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
connection.update stmt
|
40
|
+
unscoped.where(primary_key => object.id).update_all(
|
41
|
+
counter_name => object.send(counter_association).count(:all)
|
42
|
+
)
|
44
43
|
end
|
45
44
|
return true
|
46
45
|
end
|
47
46
|
|
48
47
|
# A generic "counter updater" implementation, intended primarily to be
|
49
|
-
# used by increment_counter and decrement_counter, but which may also
|
48
|
+
# used by #increment_counter and #decrement_counter, but which may also
|
50
49
|
# be useful on its own. It simply does a direct SQL update for the record
|
51
50
|
# with the given ID, altering the given hash of counters by the amount
|
52
51
|
# given by the corresponding value:
|
53
52
|
#
|
54
53
|
# ==== Parameters
|
55
54
|
#
|
56
|
-
# * +id+ - The id of the object you wish to update a counter on or an
|
55
|
+
# * +id+ - The id of the object you wish to update a counter on or an array of ids.
|
57
56
|
# * +counters+ - A Hash containing the names of the fields
|
58
57
|
# to update as keys and the amount to update the field by as values.
|
59
58
|
#
|
@@ -87,14 +86,14 @@ module ActiveRecord
|
|
87
86
|
# Increment a numeric field by one, via a direct SQL update.
|
88
87
|
#
|
89
88
|
# This method is used primarily for maintaining counter_cache columns that are
|
90
|
-
# used to store aggregate values. For example, a DiscussionBoard may cache
|
89
|
+
# used to store aggregate values. For example, a +DiscussionBoard+ may cache
|
91
90
|
# posts_count and comments_count to avoid running an SQL query to calculate the
|
92
91
|
# number of posts and comments there are, each time it is displayed.
|
93
92
|
#
|
94
93
|
# ==== Parameters
|
95
94
|
#
|
96
95
|
# * +counter_name+ - The name of the field that should be incremented.
|
97
|
-
# * +id+ - The id of the object that should be incremented or an
|
96
|
+
# * +id+ - The id of the object that should be incremented or an array of ids.
|
98
97
|
#
|
99
98
|
# ==== Examples
|
100
99
|
#
|
@@ -106,13 +105,13 @@ module ActiveRecord
|
|
106
105
|
|
107
106
|
# Decrement a numeric field by one, via a direct SQL update.
|
108
107
|
#
|
109
|
-
# This works the same as increment_counter but reduces the column value by
|
108
|
+
# This works the same as #increment_counter but reduces the column value by
|
110
109
|
# 1 instead of increasing it.
|
111
110
|
#
|
112
111
|
# ==== Parameters
|
113
112
|
#
|
114
113
|
# * +counter_name+ - The name of the field that should be decremented.
|
115
|
-
# * +id+ - The id of the object that should be decremented or an
|
114
|
+
# * +id+ - The id of the object that should be decremented or an array of ids.
|
116
115
|
#
|
117
116
|
# ==== Examples
|
118
117
|
#
|
@@ -123,16 +122,6 @@ module ActiveRecord
|
|
123
122
|
end
|
124
123
|
end
|
125
124
|
|
126
|
-
protected
|
127
|
-
|
128
|
-
def actually_destroyed?
|
129
|
-
@_actually_destroyed
|
130
|
-
end
|
131
|
-
|
132
|
-
def clear_destroy_state
|
133
|
-
@_actually_destroyed = nil
|
134
|
-
end
|
135
|
-
|
136
125
|
private
|
137
126
|
|
138
127
|
def _create_record(*)
|