activerecord 5.2.4.rc1 → 6.0.0.rc2
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 +597 -586
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +9 -2
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations.rb +19 -14
- data/lib/active_record/associations/association.rb +52 -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/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +6 -21
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -10
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- 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 +24 -28
- data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +40 -32
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- 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 +28 -100
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- 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 +17 -24
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +5 -9
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +89 -16
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +133 -54
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +172 -41
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -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/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -141
- data/lib/active_record/connection_handling.rb +149 -27
- data/lib/active_record/core.rb +100 -60
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +204 -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 +79 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +28 -7
- data/lib/active_record/errors.rb +15 -7
- 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 +13 -3
- data/lib/active_record/insert_all.rb +180 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +90 -0
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/migration.rb +87 -76
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +76 -49
- 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 +228 -24
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +32 -20
- data/lib/active_record/railtie.rb +80 -43
- 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 +193 -46
- data/lib/active_record/reflection.rb +32 -30
- data/lib/active_record/relation.rb +310 -80
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +53 -45
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +13 -26
- data/lib/active_record/relation/merger.rb +11 -20
- 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 +13 -8
- data/lib/active_record/relation/query_methods.rb +165 -53
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- 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 +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/scoping/default.rb +4 -5
- data/lib/active_record/scoping/named.rb +19 -15
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +159 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- 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 +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +57 -66
- 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 +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/arel.rb +51 -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 +68 -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/comment.rb +29 -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 +67 -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 +45 -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_list.rb +9 -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 +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -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/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +108 -26
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -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,204 @@
|
|
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 <tt>include_replicas: true</tt>.
|
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 (i.e. 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
|
+
return configs if configs.is_a?(Array)
|
106
|
+
|
107
|
+
build_db_config = configs.each_pair.flat_map do |env_name, config|
|
108
|
+
walk_configs(env_name.to_s, "primary", config)
|
109
|
+
end.flatten.compact
|
110
|
+
|
111
|
+
if url = ENV["DATABASE_URL"]
|
112
|
+
build_url_config(url, build_db_config)
|
113
|
+
else
|
114
|
+
build_db_config
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def walk_configs(env_name, spec_name, config)
|
119
|
+
case config
|
120
|
+
when String
|
121
|
+
build_db_config_from_string(env_name, spec_name, config)
|
122
|
+
when Hash
|
123
|
+
build_db_config_from_hash(env_name, spec_name, config.stringify_keys)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def build_db_config_from_string(env_name, spec_name, config)
|
128
|
+
url = config
|
129
|
+
uri = URI.parse(url)
|
130
|
+
if uri.try(:scheme)
|
131
|
+
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url)
|
132
|
+
end
|
133
|
+
rescue URI::InvalidURIError
|
134
|
+
ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
|
135
|
+
end
|
136
|
+
|
137
|
+
def build_db_config_from_hash(env_name, spec_name, config)
|
138
|
+
if config.has_key?("url")
|
139
|
+
url = config["url"]
|
140
|
+
config_without_url = config.dup
|
141
|
+
config_without_url.delete "url"
|
142
|
+
|
143
|
+
ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url, config_without_url)
|
144
|
+
elsif config["database"] || config["adapter"] || ENV["DATABASE_URL"]
|
145
|
+
ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
|
146
|
+
else
|
147
|
+
config.each_pair.map do |sub_spec_name, sub_config|
|
148
|
+
walk_configs(env_name, sub_spec_name, sub_config)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def build_url_config(url, configs)
|
154
|
+
env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
|
155
|
+
|
156
|
+
if configs.find(&:for_current_env?)
|
157
|
+
configs.map do |config|
|
158
|
+
if config.url_config?
|
159
|
+
config
|
160
|
+
else
|
161
|
+
ActiveRecord::DatabaseConfigurations::UrlConfig.new(config.env_name, config.spec_name, url, config.config)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
else
|
165
|
+
configs + [ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, "primary", url)]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def method_missing(method, *args, &blk)
|
170
|
+
case method
|
171
|
+
when :each, :first
|
172
|
+
throw_getter_deprecation(method)
|
173
|
+
configurations.send(method, *args, &blk)
|
174
|
+
when :fetch
|
175
|
+
throw_getter_deprecation(method)
|
176
|
+
configs_for(env_name: args.first)
|
177
|
+
when :values
|
178
|
+
throw_getter_deprecation(method)
|
179
|
+
configurations.map(&:config)
|
180
|
+
when :[]=
|
181
|
+
throw_setter_deprecation(method)
|
182
|
+
|
183
|
+
env_name = args[0]
|
184
|
+
config = args[1]
|
185
|
+
|
186
|
+
remaining_configs = configurations.reject { |db_config| db_config.env_name == env_name }
|
187
|
+
new_config = build_configs(env_name => config)
|
188
|
+
new_configs = remaining_configs + new_config
|
189
|
+
|
190
|
+
ActiveRecord::Base.configurations = new_configs
|
191
|
+
else
|
192
|
+
raise NotImplementedError, "`ActiveRecord::Base.configurations` in Rails 6 now returns an object instead of a hash. The `#{method}` method is not supported. Please use `configs_for` or consult the documentation for supported methods."
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def throw_setter_deprecation(method)
|
197
|
+
ActiveSupport::Deprecation.warn("Setting `ActiveRecord::Base.configurations` with `#{method}` is deprecated. Use `ActiveRecord::Base.configurations=` directly to set the configurations instead.")
|
198
|
+
end
|
199
|
+
|
200
|
+
def throw_getter_deprecation(method)
|
201
|
+
ActiveSupport::Deprecation.warn("`ActiveRecord::Base.configurations` no longer returns a hash. Methods that act on the hash like `#{method}` are deprecated and will be removed in Rails 6.1. Use the `configs_for` method to collect and iterate over the database configurations.")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
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
|
18
|
+
#
|
19
|
+
# * <tt>:env_name</tt> - The Rails environment, i.e. "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,79 @@
|
|
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
|
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
|
+
|
60
|
+
def build_url_hash(url)
|
61
|
+
if url.nil? || /^jdbc:/.match?(url)
|
62
|
+
{ "url" => url }
|
63
|
+
else
|
64
|
+
ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new(url).to_hash
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_config(original_config, url)
|
69
|
+
hash = build_url_hash(url)
|
70
|
+
|
71
|
+
if original_config[env_name]
|
72
|
+
original_config[env_name].merge(hash)
|
73
|
+
else
|
74
|
+
original_config.merge(hash)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -53,7 +53,7 @@ module ActiveRecord
|
|
53
53
|
@model = model
|
54
54
|
@name = name.to_s
|
55
55
|
@attribute_names = @name.match(self.class.pattern)[1].split("_and_")
|
56
|
-
@attribute_names.map! { |
|
56
|
+
@attribute_names.map! { |name| @model.attribute_aliases[name] || name }
|
57
57
|
end
|
58
58
|
|
59
59
|
def valid?
|
data/lib/active_record/enum.rb
CHANGED
@@ -31,7 +31,9 @@ module ActiveRecord
|
|
31
31
|
# as well. With the above example:
|
32
32
|
#
|
33
33
|
# Conversation.active
|
34
|
+
# Conversation.not_active
|
34
35
|
# Conversation.archived
|
36
|
+
# Conversation.not_archived
|
35
37
|
#
|
36
38
|
# Of course, you can also query them directly if the scopes don't fit your
|
37
39
|
# needs:
|
@@ -141,10 +143,7 @@ module ActiveRecord
|
|
141
143
|
end
|
142
144
|
end
|
143
145
|
|
144
|
-
|
145
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
146
|
-
protected
|
147
|
-
|
146
|
+
private
|
148
147
|
attr_reader :name, :mapping, :subtype
|
149
148
|
end
|
150
149
|
|
@@ -152,14 +151,16 @@ module ActiveRecord
|
|
152
151
|
klass = self
|
153
152
|
enum_prefix = definitions.delete(:_prefix)
|
154
153
|
enum_suffix = definitions.delete(:_suffix)
|
154
|
+
enum_scopes = definitions.delete(:_scopes)
|
155
155
|
definitions.each do |name, values|
|
156
|
+
assert_valid_enum_definition_values(values)
|
156
157
|
# statuses = { }
|
157
158
|
enum_values = ActiveSupport::HashWithIndifferentAccess.new
|
158
159
|
name = name.to_s
|
159
160
|
|
160
161
|
# def self.statuses() statuses end
|
161
162
|
detect_enum_conflict!(name, name.pluralize, true)
|
162
|
-
singleton_class.
|
163
|
+
singleton_class.define_method(name.pluralize) { enum_values }
|
163
164
|
defined_enums[name] = enum_values
|
164
165
|
|
165
166
|
detect_enum_conflict!(name, name)
|
@@ -197,8 +198,14 @@ module ActiveRecord
|
|
197
198
|
define_method("#{value_method_name}!") { update!(attr => value) }
|
198
199
|
|
199
200
|
# scope :active, -> { where(status: 0) }
|
200
|
-
|
201
|
-
|
201
|
+
# scope :not_active, -> { where.not(status: 0) }
|
202
|
+
if enum_scopes != false
|
203
|
+
klass.send(:detect_enum_conflict!, name, value_method_name, true)
|
204
|
+
klass.scope value_method_name, -> { where(attr => value) }
|
205
|
+
|
206
|
+
klass.send(:detect_enum_conflict!, name, "not_#{value_method_name}", true)
|
207
|
+
klass.scope "not_#{value_method_name}", -> { where.not(attr => value) }
|
208
|
+
end
|
202
209
|
end
|
203
210
|
end
|
204
211
|
enum_values.freeze
|
@@ -214,10 +221,24 @@ module ActiveRecord
|
|
214
221
|
end
|
215
222
|
end
|
216
223
|
|
224
|
+
def assert_valid_enum_definition_values(values)
|
225
|
+
unless values.is_a?(Hash) || values.all? { |v| v.is_a?(Symbol) } || values.all? { |v| v.is_a?(String) }
|
226
|
+
error_message = <<~MSG
|
227
|
+
Enum values #{values} must be either a hash, an array of symbols, or an array of strings.
|
228
|
+
MSG
|
229
|
+
raise ArgumentError, error_message
|
230
|
+
end
|
231
|
+
|
232
|
+
if values.is_a?(Hash) && values.keys.any?(&:blank?) || values.is_a?(Array) && values.any?(&:blank?)
|
233
|
+
raise ArgumentError, "Enum label name must not be blank."
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
217
237
|
ENUM_CONFLICT_MESSAGE = \
|
218
238
|
"You tried to define an enum named \"%{enum}\" on the model \"%{klass}\", but " \
|
219
239
|
"this will generate a %{type} method \"%{method}\", which is already defined " \
|
220
240
|
"by %{source}."
|
241
|
+
private_constant :ENUM_CONFLICT_MESSAGE
|
221
242
|
|
222
243
|
def detect_enum_conflict!(enum_name, method_name, klass_method = false)
|
223
244
|
if klass_method && dangerous_class_method?(method_name)
|