activerecord 5.2.4.5 → 6.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 +4 -4
- data/CHANGELOG.md +299 -739
- data/MIT-LICENSE +3 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations.rb +16 -12
- data/lib/active_record/associations/association.rb +35 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/belongs_to.rb +14 -50
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/collection_association.rb +11 -25
- data/lib/active_record/associations/collection_proxy.rb +32 -6
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +25 -18
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +15 -20
- data/lib/active_record/associations/join_dependency/join_association.rb +11 -26
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +32 -29
- data/lib/active_record/associations/preloader/association.rb +1 -2
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +34 -56
- data/lib/active_record/attribute_methods/dirty.rb +64 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -7
- data/lib/active_record/attribute_methods/read.rb +16 -48
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +15 -16
- data/lib/active_record/autosave_association.rb +7 -21
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/callbacks.rb +3 -17
- data/lib/active_record/collection_cache_key.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +13 -36
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +25 -84
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +5 -11
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +0 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -27
- data/lib/active_record/connection_adapters/abstract/transaction.rb +81 -52
- data/lib/active_record/connection_adapters/abstract_adapter.rb +95 -31
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +5 -9
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +65 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +16 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
- data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
- data/lib/active_record/connection_handling.rb +132 -26
- data/lib/active_record/core.rb +76 -43
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +184 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +74 -0
- data/lib/active_record/enum.rb +22 -7
- data/lib/active_record/errors.rb +24 -21
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +140 -472
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +12 -2
- data/lib/active_record/integration.rb +56 -16
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/migration.rb +38 -37
- data/lib/active_record/migration/command_recorder.rb +35 -5
- data/lib/active_record/migration/compatibility.rb +34 -16
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +18 -7
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +19 -11
- data/lib/active_record/railtie.rb +71 -42
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +94 -43
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation.rb +150 -69
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +38 -28
- data/lib/active_record/relation/delegation.rb +4 -13
- data/lib/active_record/relation/finder_methods.rb +12 -25
- data/lib/active_record/relation/merger.rb +2 -6
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +15 -12
- data/lib/active_record/relation/query_methods.rb +29 -52
- data/lib/active_record/relation/where_clause.rb +4 -0
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +2 -39
- data/lib/active_record/schema.rb +1 -10
- data/lib/active_record/schema_dumper.rb +12 -6
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/scoping/default.rb +10 -3
- data/lib/active_record/scoping/named.rb +10 -14
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +39 -8
- data/lib/active_record/table_metadata.rb +1 -4
- data/lib/active_record/tasks/database_tasks.rb +89 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +38 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/transactions.rb +3 -22
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +1 -6
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +13 -25
- data/lib/arel.rb +44 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +67 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +63 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values.rb +16 -0
- data/lib/arel/nodes/values_list.rb +24 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +199 -0
- data/lib/arel/visitors/dot.rb +292 -0
- data/lib/arel/visitors/ibm_db.rb +21 -0
- data/lib/arel/visitors/informix.rb +56 -0
- data/lib/arel/visitors/mssql.rb +143 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +67 -0
- data/lib/arel/visitors/postgresql.rb +116 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +913 -0
- data/lib/arel/visitors/visitor.rb +42 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- metadata +104 -26
data/lib/active_record/core.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/hash/indifferent_access"
|
4
4
|
require "active_support/core_ext/string/filters"
|
5
|
+
require "active_support/parameter_filter"
|
5
6
|
require "concurrent/map"
|
6
7
|
|
7
8
|
module ActiveRecord
|
@@ -26,7 +27,7 @@ module ActiveRecord
|
|
26
27
|
|
27
28
|
##
|
28
29
|
# Contains the database configuration - as is typically stored in config/database.yml -
|
29
|
-
# as
|
30
|
+
# as an ActiveRecord::DatabaseConfigurations object.
|
30
31
|
#
|
31
32
|
# For example, the following database.yml...
|
32
33
|
#
|
@@ -40,22 +41,18 @@ module ActiveRecord
|
|
40
41
|
#
|
41
42
|
# ...would result in ActiveRecord::Base.configurations to look like this:
|
42
43
|
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
# 'adapter' => 'sqlite3',
|
50
|
-
# 'database' => 'db/production.sqlite3'
|
51
|
-
# }
|
52
|
-
# }
|
44
|
+
# #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
|
45
|
+
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
|
46
|
+
# @spec_name="primary", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}>,
|
47
|
+
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
|
48
|
+
# @spec_name="primary", @config={"adapter"=>"mysql2", "database"=>"db/production.sqlite3"}>
|
49
|
+
# ]>
|
53
50
|
def self.configurations=(config)
|
54
|
-
@@configurations = ActiveRecord::
|
51
|
+
@@configurations = ActiveRecord::DatabaseConfigurations.new(config)
|
55
52
|
end
|
56
53
|
self.configurations = {}
|
57
54
|
|
58
|
-
# Returns fully resolved
|
55
|
+
# Returns fully resolved ActiveRecord::DatabaseConfigurations object
|
59
56
|
def self.configurations
|
60
57
|
@@configurations
|
61
58
|
end
|
@@ -99,7 +96,7 @@ module ActiveRecord
|
|
99
96
|
##
|
100
97
|
# :singleton-method:
|
101
98
|
# Specify whether schema dump should happen at the end of the
|
102
|
-
# db:migrate
|
99
|
+
# db:migrate rails command. This is true by default, which is useful for the
|
103
100
|
# development environment. This should ideally be false in the production
|
104
101
|
# environment where dumping schema is rarely needed.
|
105
102
|
mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
|
@@ -125,25 +122,25 @@ module ActiveRecord
|
|
125
122
|
|
126
123
|
mattr_accessor :belongs_to_required_by_default, instance_accessor: false
|
127
124
|
|
125
|
+
mattr_accessor :connection_handlers, instance_accessor: false, default: {}
|
126
|
+
|
128
127
|
class_attribute :default_connection_handler, instance_writer: false
|
129
128
|
|
129
|
+
self.filter_attributes = []
|
130
|
+
|
130
131
|
def self.connection_handler
|
131
|
-
|
132
|
+
Thread.current.thread_variable_get("ar_connection_handler") || default_connection_handler
|
132
133
|
end
|
133
134
|
|
134
135
|
def self.connection_handler=(handler)
|
135
|
-
|
136
|
+
Thread.current.thread_variable_set("ar_connection_handler", handler)
|
136
137
|
end
|
137
138
|
|
138
139
|
self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
|
140
|
+
self.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler }
|
139
141
|
end
|
140
142
|
|
141
|
-
module ClassMethods
|
142
|
-
def allocate
|
143
|
-
define_attribute_methods
|
144
|
-
super
|
145
|
-
end
|
146
|
-
|
143
|
+
module ClassMethods
|
147
144
|
def initialize_find_by_cache # :nodoc:
|
148
145
|
@find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
|
149
146
|
end
|
@@ -172,20 +169,16 @@ module ActiveRecord
|
|
172
169
|
where(key => params.bind).limit(1)
|
173
170
|
}
|
174
171
|
|
175
|
-
record = statement.execute([id], connection)
|
172
|
+
record = statement.execute([id], connection)&.first
|
176
173
|
unless record
|
177
174
|
raise RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}",
|
178
175
|
name, primary_key, id)
|
179
176
|
end
|
180
177
|
record
|
181
|
-
rescue ::RangeError
|
182
|
-
raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
|
183
|
-
name, primary_key)
|
184
178
|
end
|
185
179
|
|
186
180
|
def find_by(*args) # :nodoc:
|
187
|
-
return super if scope_attributes? || reflect_on_all_aggregations.any?
|
188
|
-
columns_hash.key?(inheritance_column) && base_class != self
|
181
|
+
return super if scope_attributes? || reflect_on_all_aggregations.any?
|
189
182
|
|
190
183
|
hash = args.first
|
191
184
|
|
@@ -205,11 +198,9 @@ module ActiveRecord
|
|
205
198
|
where(wheres).limit(1)
|
206
199
|
}
|
207
200
|
begin
|
208
|
-
statement.execute(hash.values, connection)
|
201
|
+
statement.execute(hash.values, connection)&.first
|
209
202
|
rescue TypeError
|
210
203
|
raise ActiveRecord::StatementInvalid
|
211
|
-
rescue ::RangeError
|
212
|
-
nil
|
213
204
|
end
|
214
205
|
end
|
215
206
|
|
@@ -221,7 +212,7 @@ module ActiveRecord
|
|
221
212
|
generated_association_methods
|
222
213
|
end
|
223
214
|
|
224
|
-
def generated_association_methods
|
215
|
+
def generated_association_methods # :nodoc:
|
225
216
|
@generated_association_methods ||= begin
|
226
217
|
mod = const_set(:GeneratedAssociationMethods, Module.new)
|
227
218
|
private_constant :GeneratedAssociationMethods
|
@@ -231,8 +222,20 @@ module ActiveRecord
|
|
231
222
|
end
|
232
223
|
end
|
233
224
|
|
225
|
+
# Returns columns which shouldn't be exposed while calling +#inspect+.
|
226
|
+
def filter_attributes
|
227
|
+
if defined?(@filter_attributes)
|
228
|
+
@filter_attributes
|
229
|
+
else
|
230
|
+
superclass.filter_attributes
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# Specifies columns which shouldn't be exposed while calling +#inspect+.
|
235
|
+
attr_writer :filter_attributes
|
236
|
+
|
234
237
|
# Returns a string like 'Post(id:integer, title:string, body:text)'
|
235
|
-
def inspect
|
238
|
+
def inspect # :nodoc:
|
236
239
|
if self == Base
|
237
240
|
super
|
238
241
|
elsif abstract_class?
|
@@ -248,7 +251,7 @@ module ActiveRecord
|
|
248
251
|
end
|
249
252
|
|
250
253
|
# Overwrite the default class equality method to provide support for decorated models.
|
251
|
-
def ===(object)
|
254
|
+
def ===(object) # :nodoc:
|
252
255
|
object.is_a?(self)
|
253
256
|
end
|
254
257
|
|
@@ -274,6 +277,10 @@ module ActiveRecord
|
|
274
277
|
TypeCaster::Map.new(self)
|
275
278
|
end
|
276
279
|
|
280
|
+
def _internal? # :nodoc:
|
281
|
+
false
|
282
|
+
end
|
283
|
+
|
277
284
|
private
|
278
285
|
|
279
286
|
def cached_find_by_statement(key, &block)
|
@@ -332,13 +339,21 @@ module ActiveRecord
|
|
332
339
|
# post = Post.allocate
|
333
340
|
# post.init_with(coder)
|
334
341
|
# post.title # => 'hello world'
|
335
|
-
def init_with(coder)
|
342
|
+
def init_with(coder, &block)
|
336
343
|
coder = LegacyYamlAdapter.convert(self.class, coder)
|
337
|
-
|
344
|
+
attributes = self.class.yaml_encoder.decode(coder)
|
345
|
+
init_with_attributes(attributes, coder["new_record"], &block)
|
346
|
+
end
|
338
347
|
|
348
|
+
##
|
349
|
+
# Initialize an empty model object from +attributes+.
|
350
|
+
# +attributes+ should be an attributes object, and unlike the
|
351
|
+
# `initialize` method, no assignment calls are made per attribute.
|
352
|
+
def init_with_attributes(attributes, new_record = false) # :nodoc:
|
339
353
|
init_internals
|
340
354
|
|
341
|
-
@new_record =
|
355
|
+
@new_record = new_record
|
356
|
+
@attributes = attributes
|
342
357
|
|
343
358
|
self.class.define_attribute_methods
|
344
359
|
|
@@ -480,7 +495,14 @@ module ActiveRecord
|
|
480
495
|
inspection = if defined?(@attributes) && @attributes
|
481
496
|
self.class.attribute_names.collect do |name|
|
482
497
|
if has_attribute?(name)
|
483
|
-
|
498
|
+
attr = _read_attribute(name)
|
499
|
+
value = if attr.nil?
|
500
|
+
attr.inspect
|
501
|
+
else
|
502
|
+
attr = format_for_inspect(attr)
|
503
|
+
inspection_filter.filter_param(name, attr)
|
504
|
+
end
|
505
|
+
"#{name}: #{value}"
|
484
506
|
end
|
485
507
|
end.compact.join(", ")
|
486
508
|
else
|
@@ -496,15 +518,16 @@ module ActiveRecord
|
|
496
518
|
return super if custom_inspect_method_defined?
|
497
519
|
pp.object_address_group(self) do
|
498
520
|
if defined?(@attributes) && @attributes
|
499
|
-
|
500
|
-
pp.seplist(
|
501
|
-
column_value = read_attribute(column_name)
|
521
|
+
attr_names = self.class.attribute_names.select { |name| has_attribute?(name) }
|
522
|
+
pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
|
502
523
|
pp.breakable " "
|
503
524
|
pp.group(1) do
|
504
|
-
pp.text
|
525
|
+
pp.text attr_name
|
505
526
|
pp.text ":"
|
506
527
|
pp.breakable
|
507
|
-
|
528
|
+
value = _read_attribute(attr_name)
|
529
|
+
value = inspection_filter.filter_param(attr_name, value) unless value.nil?
|
530
|
+
pp.pp value
|
508
531
|
end
|
509
532
|
end
|
510
533
|
else
|
@@ -555,5 +578,15 @@ module ActiveRecord
|
|
555
578
|
def custom_inspect_method_defined?
|
556
579
|
self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
|
557
580
|
end
|
581
|
+
|
582
|
+
def inspection_filter
|
583
|
+
@inspection_filter ||= begin
|
584
|
+
mask = DelegateClass(::String).new(ActiveSupport::ParameterFilter::FILTERED)
|
585
|
+
def mask.pretty_print(pp)
|
586
|
+
pp.text __getobj__
|
587
|
+
end
|
588
|
+
ActiveSupport::ParameterFilter.new(self.class.filter_attributes, mask: mask)
|
589
|
+
end
|
590
|
+
end
|
558
591
|
end
|
559
592
|
end
|
@@ -102,27 +102,7 @@ module ActiveRecord
|
|
102
102
|
# # `updated_at` = '2016-10-13T09:59:23-05:00'
|
103
103
|
# # WHERE id IN (10, 15)
|
104
104
|
def update_counters(id, counters)
|
105
|
-
|
106
|
-
|
107
|
-
updates = counters.map do |counter_name, value|
|
108
|
-
operator = value < 0 ? "-" : "+"
|
109
|
-
quoted_column = connection.quote_column_name(counter_name)
|
110
|
-
"#{quoted_column} = COALESCE(#{quoted_column}, 0) #{operator} #{value.abs}"
|
111
|
-
end
|
112
|
-
|
113
|
-
if touch
|
114
|
-
names = touch if touch != true
|
115
|
-
touch_updates = touch_attributes_with_time(*names)
|
116
|
-
updates << sanitize_sql_for_assignment(touch_updates) unless touch_updates.empty?
|
117
|
-
end
|
118
|
-
|
119
|
-
if id.is_a?(Relation) && self == id.klass
|
120
|
-
relation = id
|
121
|
-
else
|
122
|
-
relation = unscoped.where!(primary_key => id)
|
123
|
-
end
|
124
|
-
|
125
|
-
relation.update_all updates.join(", ")
|
105
|
+
unscoped.where!(primary_key => id).update_counters(counters)
|
126
106
|
end
|
127
107
|
|
128
108
|
# Increment a numeric field by one, via a direct SQL update.
|
@@ -179,14 +159,11 @@ module ActiveRecord
|
|
179
159
|
end
|
180
160
|
|
181
161
|
private
|
182
|
-
|
183
|
-
def _create_record(*)
|
162
|
+
def _create_record(attribute_names = self.attribute_names)
|
184
163
|
id = super
|
185
164
|
|
186
165
|
each_counter_cached_associations do |association|
|
187
|
-
|
188
|
-
association.increment_counters
|
189
|
-
end
|
166
|
+
association.increment_counters
|
190
167
|
end
|
191
168
|
|
192
169
|
id
|
@@ -199,9 +176,7 @@ module ActiveRecord
|
|
199
176
|
each_counter_cached_associations do |association|
|
200
177
|
foreign_key = association.reflection.foreign_key.to_sym
|
201
178
|
unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key
|
202
|
-
|
203
|
-
association.decrement_counters
|
204
|
-
end
|
179
|
+
association.decrement_counters
|
205
180
|
end
|
206
181
|
end
|
207
182
|
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record/database_configurations/database_config"
|
4
|
+
require "active_record/database_configurations/hash_config"
|
5
|
+
require "active_record/database_configurations/url_config"
|
6
|
+
|
7
|
+
module ActiveRecord
|
8
|
+
# ActiveRecord::DatabaseConfigurations returns an array of DatabaseConfig
|
9
|
+
# objects (either a HashConfig or UrlConfig) that are constructed from the
|
10
|
+
# application's database configuration hash or url string.
|
11
|
+
class DatabaseConfigurations
|
12
|
+
attr_reader :configurations
|
13
|
+
delegate :any?, to: :configurations
|
14
|
+
|
15
|
+
def initialize(configurations = {})
|
16
|
+
@configurations = build_configs(configurations)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Collects the configs for the environment and optionally the specification
|
20
|
+
# name passed in. To include replica configurations pass `include_replicas: true`.
|
21
|
+
#
|
22
|
+
# If a spec name is provided a single DatabaseConfig object will be
|
23
|
+
# returned, otherwise an array of DatabaseConfig objects will be
|
24
|
+
# returned that corresponds with the environment and type requested.
|
25
|
+
#
|
26
|
+
# Options:
|
27
|
+
#
|
28
|
+
# <tt>env_name:</tt> The environment name. Defaults to nil which will collect
|
29
|
+
# configs for all environments.
|
30
|
+
# <tt>spec_name:</tt> The specification name (ie primary, animals, etc.). Defaults
|
31
|
+
# to +nil+.
|
32
|
+
# <tt>include_replicas:</tt> Determines whether to include replicas in
|
33
|
+
# the returned list. Most of the time we're only iterating over the write
|
34
|
+
# connection (i.e. migrations don't need to run for the write and read connection).
|
35
|
+
# Defaults to +false+.
|
36
|
+
def configs_for(env_name: nil, spec_name: nil, include_replicas: false)
|
37
|
+
configs = env_with_configs(env_name)
|
38
|
+
|
39
|
+
unless include_replicas
|
40
|
+
configs = configs.select do |db_config|
|
41
|
+
!db_config.replica?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if spec_name
|
46
|
+
configs.find do |db_config|
|
47
|
+
db_config.spec_name == spec_name
|
48
|
+
end
|
49
|
+
else
|
50
|
+
configs
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the config hash that corresponds with the environment
|
55
|
+
#
|
56
|
+
# If the application has multiple databases `default_hash` will
|
57
|
+
# return the first config hash for the environment.
|
58
|
+
#
|
59
|
+
# { database: "my_db", adapter: "mysql2" }
|
60
|
+
def default_hash(env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s)
|
61
|
+
default = find_db_config(env)
|
62
|
+
default.config if default
|
63
|
+
end
|
64
|
+
alias :[] :default_hash
|
65
|
+
|
66
|
+
# Returns a single DatabaseConfig object based on the requested environment.
|
67
|
+
#
|
68
|
+
# If the application has multiple databases `find_db_config` will return
|
69
|
+
# the first DatabaseConfig for the environment.
|
70
|
+
def find_db_config(env)
|
71
|
+
configurations.find do |db_config|
|
72
|
+
db_config.env_name == env.to_s ||
|
73
|
+
(db_config.for_current_env? && db_config.spec_name == env.to_s)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns the DatabaseConfigurations object as a Hash.
|
78
|
+
def to_h
|
79
|
+
configs = configurations.reverse.inject({}) do |memo, db_config|
|
80
|
+
memo.merge(db_config.to_legacy_hash)
|
81
|
+
end
|
82
|
+
|
83
|
+
Hash[configs.to_a.reverse]
|
84
|
+
end
|
85
|
+
|
86
|
+
# Checks if the application's configurations are empty.
|
87
|
+
#
|
88
|
+
# Aliased to blank?
|
89
|
+
def empty?
|
90
|
+
configurations.empty?
|
91
|
+
end
|
92
|
+
alias :blank? :empty?
|
93
|
+
|
94
|
+
private
|
95
|
+
def env_with_configs(env = nil)
|
96
|
+
if env
|
97
|
+
configurations.select { |db_config| db_config.env_name == env }
|
98
|
+
else
|
99
|
+
configurations
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def build_configs(configs)
|
104
|
+
return configs.configurations if configs.is_a?(DatabaseConfigurations)
|
105
|
+
|
106
|
+
build_db_config = configs.each_pair.flat_map do |env_name, config|
|
107
|
+
walk_configs(env_name.to_s, "primary", config)
|
108
|
+
end.compact
|
109
|
+
|
110
|
+
if url = ENV["DATABASE_URL"]
|
111
|
+
build_url_config(url, build_db_config)
|
112
|
+
else
|
113
|
+
build_db_config
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def walk_configs(env_name, spec_name, config)
|
118
|
+
case config
|
119
|
+
when String
|
120
|
+
build_db_config_from_string(env_name, spec_name, config)
|
121
|
+
when Hash
|
122
|
+
build_db_config_from_hash(env_name, spec_name, config.stringify_keys)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def build_db_config_from_string(env_name, spec_name, config)
|
127
|
+
url = config
|
128
|
+
uri = URI.parse(url)
|
129
|
+
if uri.try(:scheme)
|
130
|
+
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url)
|
131
|
+
end
|
132
|
+
rescue URI::InvalidURIError
|
133
|
+
ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
|
134
|
+
end
|
135
|
+
|
136
|
+
def build_db_config_from_hash(env_name, spec_name, config)
|
137
|
+
if url = config["url"]
|
138
|
+
config_without_url = config.dup
|
139
|
+
config_without_url.delete "url"
|
140
|
+
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url, config_without_url)
|
141
|
+
elsif config["database"] || (config.size == 1 && config.values.all? { |v| v.is_a? String })
|
142
|
+
ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
|
143
|
+
else
|
144
|
+
config.each_pair.map do |sub_spec_name, sub_config|
|
145
|
+
walk_configs(env_name, sub_spec_name, sub_config)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def build_url_config(url, configs)
|
151
|
+
env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
|
152
|
+
|
153
|
+
if original_config = configs.find(&:for_current_env?)
|
154
|
+
if original_config.url_config?
|
155
|
+
configs
|
156
|
+
else
|
157
|
+
configs.map do |config|
|
158
|
+
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, config.spec_name, url, config.config)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
else
|
162
|
+
configs + [ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, "primary", url)]
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def method_missing(method, *args, &blk)
|
167
|
+
if Hash.method_defined?(method)
|
168
|
+
ActiveSupport::Deprecation.warn \
|
169
|
+
"Returning a hash from ActiveRecord::Base.configurations is deprecated. Therefore calling `#{method}` on the hash is also deprecated. Please switch to using the `configs_for` method instead to collect and iterate over database configurations."
|
170
|
+
end
|
171
|
+
|
172
|
+
case method
|
173
|
+
when :each, :first
|
174
|
+
configurations.send(method, *args, &blk)
|
175
|
+
when :fetch
|
176
|
+
configs_for(env_name: args.first)
|
177
|
+
when :values
|
178
|
+
configurations.map(&:config)
|
179
|
+
else
|
180
|
+
super
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|