activerecord 5.2.8.1 → 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 -816
- data/MIT-LICENSE +3 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- 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/join_association.rb +11 -26
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +15 -20
- data/lib/active_record/associations/preloader/association.rb +1 -2
- data/lib/active_record/associations/preloader.rb +32 -29
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations.rb +16 -12
- data/lib/active_record/attribute_assignment.rb +7 -10
- 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/attribute_methods.rb +34 -56
- 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/coders/yaml_column.rb +1 -13
- 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 +75 -52
- data/lib/active_record/counter_cache.rb +4 -29
- 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/database_configurations.rb +184 -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/command_recorder.rb +35 -5
- data/lib/active_record/migration/compatibility.rb +34 -16
- data/lib/active_record/migration.rb +38 -37
- 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 -60
- 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/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/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/predicate_builder.rb +4 -6
- 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/relation.rb +150 -69
- 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/default.rb +10 -3
- data/lib/active_record/scoping/named.rb +10 -14
- data/lib/active_record/scoping.rb +9 -8
- 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/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type.rb +3 -4
- 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/active_record.rb +2 -1
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -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/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/nodes.rb +67 -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/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/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +44 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- metadata +107 -29
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,35 +122,25 @@ module ActiveRecord
|
|
125
122
|
|
126
123
|
mattr_accessor :belongs_to_required_by_default, instance_accessor: false
|
127
124
|
|
128
|
-
|
129
|
-
# :singleton-method:
|
130
|
-
# Application configurable boolean that instructs the YAML Coder to use
|
131
|
-
# an unsafe load if set to true.
|
132
|
-
mattr_accessor :use_yaml_unsafe_load, instance_writer: false, default: false
|
133
|
-
|
134
|
-
# Application configurable array that provides additional permitted classes
|
135
|
-
# to Psych safe_load in the YAML Coder
|
136
|
-
mattr_accessor :yaml_column_permitted_classes, instance_writer: false, default: []
|
125
|
+
mattr_accessor :connection_handlers, instance_accessor: false, default: {}
|
137
126
|
|
138
127
|
class_attribute :default_connection_handler, instance_writer: false
|
139
128
|
|
129
|
+
self.filter_attributes = []
|
130
|
+
|
140
131
|
def self.connection_handler
|
141
|
-
|
132
|
+
Thread.current.thread_variable_get("ar_connection_handler") || default_connection_handler
|
142
133
|
end
|
143
134
|
|
144
135
|
def self.connection_handler=(handler)
|
145
|
-
|
136
|
+
Thread.current.thread_variable_set("ar_connection_handler", handler)
|
146
137
|
end
|
147
138
|
|
148
139
|
self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
|
140
|
+
self.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler }
|
149
141
|
end
|
150
142
|
|
151
|
-
module ClassMethods
|
152
|
-
def allocate
|
153
|
-
define_attribute_methods
|
154
|
-
super
|
155
|
-
end
|
156
|
-
|
143
|
+
module ClassMethods
|
157
144
|
def initialize_find_by_cache # :nodoc:
|
158
145
|
@find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
|
159
146
|
end
|
@@ -182,20 +169,16 @@ module ActiveRecord
|
|
182
169
|
where(key => params.bind).limit(1)
|
183
170
|
}
|
184
171
|
|
185
|
-
record = statement.execute([id], connection)
|
172
|
+
record = statement.execute([id], connection)&.first
|
186
173
|
unless record
|
187
174
|
raise RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}",
|
188
175
|
name, primary_key, id)
|
189
176
|
end
|
190
177
|
record
|
191
|
-
rescue ::RangeError
|
192
|
-
raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
|
193
|
-
name, primary_key)
|
194
178
|
end
|
195
179
|
|
196
180
|
def find_by(*args) # :nodoc:
|
197
|
-
return super if scope_attributes? || reflect_on_all_aggregations.any?
|
198
|
-
columns_hash.key?(inheritance_column) && base_class != self
|
181
|
+
return super if scope_attributes? || reflect_on_all_aggregations.any?
|
199
182
|
|
200
183
|
hash = args.first
|
201
184
|
|
@@ -215,11 +198,9 @@ module ActiveRecord
|
|
215
198
|
where(wheres).limit(1)
|
216
199
|
}
|
217
200
|
begin
|
218
|
-
statement.execute(hash.values, connection)
|
201
|
+
statement.execute(hash.values, connection)&.first
|
219
202
|
rescue TypeError
|
220
203
|
raise ActiveRecord::StatementInvalid
|
221
|
-
rescue ::RangeError
|
222
|
-
nil
|
223
204
|
end
|
224
205
|
end
|
225
206
|
|
@@ -231,7 +212,7 @@ module ActiveRecord
|
|
231
212
|
generated_association_methods
|
232
213
|
end
|
233
214
|
|
234
|
-
def generated_association_methods
|
215
|
+
def generated_association_methods # :nodoc:
|
235
216
|
@generated_association_methods ||= begin
|
236
217
|
mod = const_set(:GeneratedAssociationMethods, Module.new)
|
237
218
|
private_constant :GeneratedAssociationMethods
|
@@ -241,8 +222,20 @@ module ActiveRecord
|
|
241
222
|
end
|
242
223
|
end
|
243
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
|
+
|
244
237
|
# Returns a string like 'Post(id:integer, title:string, body:text)'
|
245
|
-
def inspect
|
238
|
+
def inspect # :nodoc:
|
246
239
|
if self == Base
|
247
240
|
super
|
248
241
|
elsif abstract_class?
|
@@ -258,7 +251,7 @@ module ActiveRecord
|
|
258
251
|
end
|
259
252
|
|
260
253
|
# Overwrite the default class equality method to provide support for decorated models.
|
261
|
-
def ===(object)
|
254
|
+
def ===(object) # :nodoc:
|
262
255
|
object.is_a?(self)
|
263
256
|
end
|
264
257
|
|
@@ -284,6 +277,10 @@ module ActiveRecord
|
|
284
277
|
TypeCaster::Map.new(self)
|
285
278
|
end
|
286
279
|
|
280
|
+
def _internal? # :nodoc:
|
281
|
+
false
|
282
|
+
end
|
283
|
+
|
287
284
|
private
|
288
285
|
|
289
286
|
def cached_find_by_statement(key, &block)
|
@@ -342,13 +339,21 @@ module ActiveRecord
|
|
342
339
|
# post = Post.allocate
|
343
340
|
# post.init_with(coder)
|
344
341
|
# post.title # => 'hello world'
|
345
|
-
def init_with(coder)
|
342
|
+
def init_with(coder, &block)
|
346
343
|
coder = LegacyYamlAdapter.convert(self.class, coder)
|
347
|
-
|
344
|
+
attributes = self.class.yaml_encoder.decode(coder)
|
345
|
+
init_with_attributes(attributes, coder["new_record"], &block)
|
346
|
+
end
|
348
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:
|
349
353
|
init_internals
|
350
354
|
|
351
|
-
@new_record =
|
355
|
+
@new_record = new_record
|
356
|
+
@attributes = attributes
|
352
357
|
|
353
358
|
self.class.define_attribute_methods
|
354
359
|
|
@@ -490,7 +495,14 @@ module ActiveRecord
|
|
490
495
|
inspection = if defined?(@attributes) && @attributes
|
491
496
|
self.class.attribute_names.collect do |name|
|
492
497
|
if has_attribute?(name)
|
493
|
-
|
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}"
|
494
506
|
end
|
495
507
|
end.compact.join(", ")
|
496
508
|
else
|
@@ -506,15 +518,16 @@ module ActiveRecord
|
|
506
518
|
return super if custom_inspect_method_defined?
|
507
519
|
pp.object_address_group(self) do
|
508
520
|
if defined?(@attributes) && @attributes
|
509
|
-
|
510
|
-
pp.seplist(
|
511
|
-
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|
|
512
523
|
pp.breakable " "
|
513
524
|
pp.group(1) do
|
514
|
-
pp.text
|
525
|
+
pp.text attr_name
|
515
526
|
pp.text ":"
|
516
527
|
pp.breakable
|
517
|
-
|
528
|
+
value = _read_attribute(attr_name)
|
529
|
+
value = inspection_filter.filter_param(attr_name, value) unless value.nil?
|
530
|
+
pp.pp value
|
518
531
|
end
|
519
532
|
end
|
520
533
|
else
|
@@ -565,5 +578,15 @@ module ActiveRecord
|
|
565
578
|
def custom_inspect_method_defined?
|
566
579
|
self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
|
567
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
|
568
591
|
end
|
569
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,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class DatabaseConfigurations
|
5
|
+
# ActiveRecord::Base.configurations will return either a HashConfig or
|
6
|
+
# UrlConfig respectively. It will never return a DatabaseConfig object,
|
7
|
+
# as this is the parent class for the types of database configuration objects.
|
8
|
+
class DatabaseConfig # :nodoc:
|
9
|
+
attr_reader :env_name, :spec_name
|
10
|
+
|
11
|
+
def initialize(env_name, spec_name)
|
12
|
+
@env_name = env_name
|
13
|
+
@spec_name = spec_name
|
14
|
+
end
|
15
|
+
|
16
|
+
def replica?
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
def migrations_paths
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
|
24
|
+
def url_config?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_legacy_hash
|
29
|
+
{ env_name => config }
|
30
|
+
end
|
31
|
+
|
32
|
+
def for_current_env?
|
33
|
+
env_name == ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class DatabaseConfigurations
|
5
|
+
# A HashConfig object is created for each database configuration entry that
|
6
|
+
# is created from a hash.
|
7
|
+
#
|
8
|
+
# A hash config:
|
9
|
+
#
|
10
|
+
# { "development" => { "database" => "db_name" } }
|
11
|
+
#
|
12
|
+
# Becomes:
|
13
|
+
#
|
14
|
+
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10
|
15
|
+
# @env_name="development", @spec_name="primary", @config={"database"=>"db_name"}>
|
16
|
+
#
|
17
|
+
# Options are:
|
18
|
+
#
|
19
|
+
# <tt>:env_name</tt> - The Rails environment, ie "development"
|
20
|
+
# <tt>:spec_name</tt> - The specification name. In a standard two-tier
|
21
|
+
# database configuration this will default to "primary". In a multiple
|
22
|
+
# database three-tier database configuration this corresponds to the name
|
23
|
+
# used in the second tier, for example "primary_readonly".
|
24
|
+
# <tt>:config</tt> - The config hash. This is the hash that contains the
|
25
|
+
# database adapter, name, and other important information for database
|
26
|
+
# connections.
|
27
|
+
class HashConfig < DatabaseConfig
|
28
|
+
attr_reader :config
|
29
|
+
|
30
|
+
def initialize(env_name, spec_name, config)
|
31
|
+
super(env_name, spec_name)
|
32
|
+
@config = config
|
33
|
+
end
|
34
|
+
|
35
|
+
# Determines whether a database configuration is for a replica / readonly
|
36
|
+
# connection. If the `replica` key is present in the config, `replica?` will
|
37
|
+
# return +true+.
|
38
|
+
def replica?
|
39
|
+
config["replica"]
|
40
|
+
end
|
41
|
+
|
42
|
+
# The migrations paths for a database configuration. If the
|
43
|
+
# `migrations_paths` key is present in the config, `migrations_paths`
|
44
|
+
# will return its value.
|
45
|
+
def migrations_paths
|
46
|
+
config["migrations_paths"]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class DatabaseConfigurations
|
5
|
+
# A UrlConfig object is created for each database configuration
|
6
|
+
# entry that is created from a URL. This can either be a URL string
|
7
|
+
# or a hash with a URL in place of the config hash.
|
8
|
+
#
|
9
|
+
# A URL config:
|
10
|
+
#
|
11
|
+
# postgres://localhost/foo
|
12
|
+
#
|
13
|
+
# Becomes:
|
14
|
+
#
|
15
|
+
# #<ActiveRecord::DatabaseConfigurations::UrlConfig:0x00007fdc3238f340
|
16
|
+
# @env_name="default_env", @spec_name="primary",
|
17
|
+
# @config={"adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost"},
|
18
|
+
# @url="postgres://localhost/foo">
|
19
|
+
#
|
20
|
+
# Options are:
|
21
|
+
#
|
22
|
+
# <tt>:env_name</tt> - The Rails environment, ie "development"
|
23
|
+
# <tt>:spec_name</tt> - The specification name. In a standard two-tier
|
24
|
+
# database configuration this will default to "primary". In a multiple
|
25
|
+
# database three-tier database configuration this corresponds to the name
|
26
|
+
# used in the second tier, for example "primary_readonly".
|
27
|
+
# <tt>:url</tt> - The database URL.
|
28
|
+
# <tt>:config</tt> - The config hash. This is the hash that contains the
|
29
|
+
# database adapter, name, and other important information for database
|
30
|
+
# connections.
|
31
|
+
class UrlConfig < DatabaseConfig
|
32
|
+
attr_reader :url, :config
|
33
|
+
|
34
|
+
def initialize(env_name, spec_name, url, config = {})
|
35
|
+
super(env_name, spec_name)
|
36
|
+
@config = build_config(config, url)
|
37
|
+
@url = url
|
38
|
+
end
|
39
|
+
|
40
|
+
def url_config? # :nodoc:
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
# Determines whether a database configuration is for a replica / readonly
|
45
|
+
# connection. If the `replica` key is present in the config, `replica?` will
|
46
|
+
# return +true+.
|
47
|
+
def replica?
|
48
|
+
config["replica"]
|
49
|
+
end
|
50
|
+
|
51
|
+
# The migrations paths for a database configuration. If the
|
52
|
+
# `migrations_paths` key is present in the config, `migrations_paths`
|
53
|
+
# will return its value.
|
54
|
+
def migrations_paths
|
55
|
+
config["migrations_paths"]
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def build_config(original_config, url)
|
60
|
+
if /^jdbc:/.match?(url)
|
61
|
+
hash = { "url" => url }
|
62
|
+
else
|
63
|
+
hash = ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new(url).to_hash
|
64
|
+
end
|
65
|
+
|
66
|
+
if original_config[env_name]
|
67
|
+
original_config[env_name].merge(hash)
|
68
|
+
else
|
69
|
+
original_config.merge(hash)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
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
|