activerecord 6.1.7.6 → 7.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1570 -1016
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +20 -22
- data/lib/active_record/associations/collection_proxy.rb +15 -5
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +8 -5
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/preloader/association.rb +186 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +138 -100
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +8 -6
- data/lib/active_record/attribute_methods/serialization.rb +57 -19
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +19 -22
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +8 -23
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +14 -16
- data/lib/active_record/coders/yaml_column.rb +4 -8
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +52 -23
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +82 -25
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +144 -82
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +115 -85
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +37 -25
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -23
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +19 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -17
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +76 -73
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +40 -21
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -106
- data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +33 -18
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +19 -17
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +98 -36
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +49 -55
- data/lib/active_record/core.rb +123 -148
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +15 -32
- data/lib/active_record/delegated_type.rb +53 -12
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +67 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +206 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +50 -43
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +20 -23
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +5 -5
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +1 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +36 -21
- data/lib/active_record/locking/pessimistic.rb +10 -4
- data/lib/active_record/log_subscriber.rb +23 -7
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +18 -6
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +8 -9
- data/lib/active_record/migration/compatibility.rb +93 -46
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +167 -87
- data/lib/active_record/model_schema.rb +58 -59
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +231 -61
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +149 -0
- data/lib/active_record/querying.rb +16 -6
- data/lib/active_record/railtie.rb +136 -22
- data/lib/active_record/railties/controller_runtime.rb +4 -5
- data/lib/active_record/railties/databases.rake +78 -136
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +80 -49
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +6 -6
- data/lib/active_record/relation/calculations.rb +92 -60
- data/lib/active_record/relation/delegation.rb +7 -7
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +28 -11
- data/lib/active_record/relation/query_methods.rb +304 -68
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +189 -88
- data/lib/active_record/result.rb +23 -11
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +17 -12
- data/lib/active_record/schema.rb +38 -23
- data/lib/active_record/schema_dumper.rb +29 -19
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +60 -13
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +3 -3
- data/lib/active_record/store.rb +2 -2
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/table_metadata.rb +6 -2
- data/lib/active_record/tasks/database_tasks.rb +127 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +9 -6
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +12 -17
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +225 -27
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +55 -11
data/lib/arel/select_manager.rb
CHANGED
@@ -7,10 +7,8 @@ module Arel # :nodoc: all
|
|
7
7
|
STRING_OR_SYMBOL_CLASS = [Symbol, String]
|
8
8
|
|
9
9
|
def initialize(table = nil)
|
10
|
-
|
11
|
-
@ast = Nodes::SelectStatement.new
|
10
|
+
@ast = Nodes::SelectStatement.new(table)
|
12
11
|
@ctx = @ast.cores.last
|
13
|
-
from table
|
14
12
|
end
|
15
13
|
|
16
14
|
def initialize_copy(other)
|
@@ -98,7 +96,7 @@ module Arel # :nodoc: all
|
|
98
96
|
end
|
99
97
|
|
100
98
|
def froms
|
101
|
-
@ast.cores.
|
99
|
+
@ast.cores.filter_map { |x| x.from }
|
102
100
|
end
|
103
101
|
|
104
102
|
def join(relation, klass = Nodes::InnerJoin)
|
@@ -183,6 +181,14 @@ module Arel # :nodoc: all
|
|
183
181
|
@ast.orders
|
184
182
|
end
|
185
183
|
|
184
|
+
def where(expr)
|
185
|
+
if Arel::TreeManager === expr
|
186
|
+
expr = expr.ast
|
187
|
+
end
|
188
|
+
@ctx.wheres << expr
|
189
|
+
self
|
190
|
+
end
|
191
|
+
|
186
192
|
def where_sql(engine = Table.engine)
|
187
193
|
return if @ctx.wheres.empty?
|
188
194
|
|
data/lib/arel/table.rb
CHANGED
data/lib/arel/tree_manager.rb
CHANGED
@@ -40,10 +40,6 @@ module Arel # :nodoc: all
|
|
40
40
|
|
41
41
|
attr_reader :ast
|
42
42
|
|
43
|
-
def initialize
|
44
|
-
@ctx = nil
|
45
|
-
end
|
46
|
-
|
47
43
|
def to_dot
|
48
44
|
collector = Arel::Collectors::PlainString.new
|
49
45
|
collector = Visitors::Dot.new.accept @ast, collector
|
@@ -60,13 +56,5 @@ module Arel # :nodoc: all
|
|
60
56
|
super
|
61
57
|
@ast = @ast.clone
|
62
58
|
end
|
63
|
-
|
64
|
-
def where(expr)
|
65
|
-
if Arel::TreeManager === expr
|
66
|
-
expr = expr.ast
|
67
|
-
end
|
68
|
-
@ctx.wheres << expr
|
69
|
-
self
|
70
|
-
end
|
71
59
|
end
|
72
60
|
end
|
data/lib/arel/update_manager.rb
CHANGED
@@ -4,10 +4,8 @@ module Arel # :nodoc: all
|
|
4
4
|
class UpdateManager < Arel::TreeManager
|
5
5
|
include TreeManager::StatementMethods
|
6
6
|
|
7
|
-
def initialize
|
8
|
-
|
9
|
-
@ast = Nodes::UpdateStatement.new
|
10
|
-
@ctx = @ast
|
7
|
+
def initialize(table = nil)
|
8
|
+
@ast = Nodes::UpdateStatement.new(table)
|
11
9
|
end
|
12
10
|
|
13
11
|
###
|
@@ -30,5 +28,21 @@ module Arel # :nodoc: all
|
|
30
28
|
end
|
31
29
|
self
|
32
30
|
end
|
31
|
+
|
32
|
+
def group(columns)
|
33
|
+
columns.each do |column|
|
34
|
+
column = Nodes::SqlLiteral.new(column) if String === column
|
35
|
+
column = Nodes::SqlLiteral.new(column.to_s) if Symbol === column
|
36
|
+
|
37
|
+
@ast.groups.push Nodes::Group.new column
|
38
|
+
end
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def having(expr)
|
44
|
+
@ast.havings << expr
|
45
|
+
self
|
46
|
+
end
|
33
47
|
end
|
34
48
|
end
|
data/lib/arel/visitors/dot.rb
CHANGED
@@ -31,6 +31,40 @@ module Arel # :nodoc: all
|
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
34
|
+
def visit_Arel_Nodes_Function(o)
|
35
|
+
visit_edge o, "expressions"
|
36
|
+
visit_edge o, "distinct"
|
37
|
+
visit_edge o, "alias"
|
38
|
+
end
|
39
|
+
|
40
|
+
def visit_Arel_Nodes_Unary(o)
|
41
|
+
visit_edge o, "expr"
|
42
|
+
end
|
43
|
+
|
44
|
+
def visit_Arel_Nodes_Binary(o)
|
45
|
+
visit_edge o, "left"
|
46
|
+
visit_edge o, "right"
|
47
|
+
end
|
48
|
+
|
49
|
+
def visit_Arel_Nodes_UnaryOperation(o)
|
50
|
+
visit_edge o, "operator"
|
51
|
+
visit_edge o, "expr"
|
52
|
+
end
|
53
|
+
|
54
|
+
def visit_Arel_Nodes_InfixOperation(o)
|
55
|
+
visit_edge o, "operator"
|
56
|
+
visit_edge o, "left"
|
57
|
+
visit_edge o, "right"
|
58
|
+
end
|
59
|
+
|
60
|
+
def visit__regexp(o)
|
61
|
+
visit_edge o, "left"
|
62
|
+
visit_edge o, "right"
|
63
|
+
visit_edge o, "case_sensitive"
|
64
|
+
end
|
65
|
+
alias :visit_Arel_Nodes_Regexp :visit__regexp
|
66
|
+
alias :visit_Arel_Nodes_NotRegexp :visit__regexp
|
67
|
+
|
34
68
|
def visit_Arel_Nodes_Ordering(o)
|
35
69
|
visit_edge o, "expr"
|
36
70
|
end
|
@@ -53,71 +87,29 @@ module Arel # :nodoc: all
|
|
53
87
|
visit_edge o, "left"
|
54
88
|
end
|
55
89
|
|
56
|
-
def
|
57
|
-
visit_edge o, "left"
|
58
|
-
visit_edge o, "right"
|
59
|
-
end
|
60
|
-
alias :visit_Arel_Nodes_FullOuterJoin :visit_Arel_Nodes_InnerJoin
|
61
|
-
alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin
|
62
|
-
alias :visit_Arel_Nodes_RightOuterJoin :visit_Arel_Nodes_InnerJoin
|
63
|
-
|
64
|
-
def visit_Arel_Nodes_DeleteStatement(o)
|
65
|
-
visit_edge o, "relation"
|
66
|
-
visit_edge o, "wheres"
|
67
|
-
end
|
68
|
-
|
69
|
-
def unary(o)
|
70
|
-
visit_edge o, "expr"
|
71
|
-
end
|
72
|
-
alias :visit_Arel_Nodes_Group :unary
|
73
|
-
alias :visit_Arel_Nodes_Cube :unary
|
74
|
-
alias :visit_Arel_Nodes_RollUp :unary
|
75
|
-
alias :visit_Arel_Nodes_GroupingSet :unary
|
76
|
-
alias :visit_Arel_Nodes_GroupingElement :unary
|
77
|
-
alias :visit_Arel_Nodes_Grouping :unary
|
78
|
-
alias :visit_Arel_Nodes_Having :unary
|
79
|
-
alias :visit_Arel_Nodes_Limit :unary
|
80
|
-
alias :visit_Arel_Nodes_Not :unary
|
81
|
-
alias :visit_Arel_Nodes_Offset :unary
|
82
|
-
alias :visit_Arel_Nodes_On :unary
|
83
|
-
alias :visit_Arel_Nodes_UnqualifiedColumn :unary
|
84
|
-
alias :visit_Arel_Nodes_OptimizerHints :unary
|
85
|
-
alias :visit_Arel_Nodes_Preceding :unary
|
86
|
-
alias :visit_Arel_Nodes_Following :unary
|
87
|
-
alias :visit_Arel_Nodes_Rows :unary
|
88
|
-
alias :visit_Arel_Nodes_Range :unary
|
89
|
-
|
90
|
-
def window(o)
|
90
|
+
def visit_Arel_Nodes_Window(o)
|
91
91
|
visit_edge o, "partitions"
|
92
92
|
visit_edge o, "orders"
|
93
93
|
visit_edge o, "framing"
|
94
94
|
end
|
95
|
-
alias :visit_Arel_Nodes_Window :window
|
96
95
|
|
97
|
-
def
|
96
|
+
def visit_Arel_Nodes_NamedWindow(o)
|
98
97
|
visit_edge o, "partitions"
|
99
98
|
visit_edge o, "orders"
|
100
99
|
visit_edge o, "framing"
|
101
100
|
visit_edge o, "name"
|
102
101
|
end
|
103
|
-
alias :visit_Arel_Nodes_NamedWindow :named_window
|
104
102
|
|
105
|
-
def
|
106
|
-
|
107
|
-
visit_edge o, "distinct"
|
108
|
-
visit_edge o, "alias"
|
103
|
+
def visit__no_edges(o)
|
104
|
+
# intentionally left blank
|
109
105
|
end
|
110
|
-
alias :
|
111
|
-
alias :
|
112
|
-
alias :visit_Arel_Nodes_Max :function
|
113
|
-
alias :visit_Arel_Nodes_Avg :function
|
114
|
-
alias :visit_Arel_Nodes_Sum :function
|
106
|
+
alias :visit_Arel_Nodes_CurrentRow :visit__no_edges
|
107
|
+
alias :visit_Arel_Nodes_Distinct :visit__no_edges
|
115
108
|
|
116
|
-
def
|
109
|
+
def visit_Arel_Nodes_Extract(o)
|
117
110
|
visit_edge o, "expressions"
|
118
111
|
visit_edge o, "alias"
|
119
112
|
end
|
120
|
-
alias :visit_Arel_Nodes_Extract :extract
|
121
113
|
|
122
114
|
def visit_Arel_Nodes_NamedFunction(o)
|
123
115
|
visit_edge o, "name"
|
@@ -130,13 +122,19 @@ module Arel # :nodoc: all
|
|
130
122
|
visit_edge o, "relation"
|
131
123
|
visit_edge o, "columns"
|
132
124
|
visit_edge o, "values"
|
125
|
+
visit_edge o, "select"
|
133
126
|
end
|
134
127
|
|
135
128
|
def visit_Arel_Nodes_SelectCore(o)
|
136
129
|
visit_edge o, "source"
|
137
130
|
visit_edge o, "projections"
|
138
131
|
visit_edge o, "wheres"
|
139
|
-
visit_edge o,
|
132
|
+
visit_edge o, "windows"
|
133
|
+
visit_edge o, "groups"
|
134
|
+
visit_edge o, "comment"
|
135
|
+
visit_edge o, "havings"
|
136
|
+
visit_edge o, "set_quantifier"
|
137
|
+
visit_edge o, "optimizer_hints"
|
140
138
|
end
|
141
139
|
|
142
140
|
def visit_Arel_Nodes_SelectStatement(o)
|
@@ -144,12 +142,27 @@ module Arel # :nodoc: all
|
|
144
142
|
visit_edge o, "limit"
|
145
143
|
visit_edge o, "orders"
|
146
144
|
visit_edge o, "offset"
|
145
|
+
visit_edge o, "lock"
|
146
|
+
visit_edge o, "with"
|
147
147
|
end
|
148
148
|
|
149
149
|
def visit_Arel_Nodes_UpdateStatement(o)
|
150
150
|
visit_edge o, "relation"
|
151
151
|
visit_edge o, "wheres"
|
152
152
|
visit_edge o, "values"
|
153
|
+
visit_edge o, "orders"
|
154
|
+
visit_edge o, "limit"
|
155
|
+
visit_edge o, "offset"
|
156
|
+
visit_edge o, "key"
|
157
|
+
end
|
158
|
+
|
159
|
+
def visit_Arel_Nodes_DeleteStatement(o)
|
160
|
+
visit_edge o, "relation"
|
161
|
+
visit_edge o, "wheres"
|
162
|
+
visit_edge o, "orders"
|
163
|
+
visit_edge o, "limit"
|
164
|
+
visit_edge o, "offset"
|
165
|
+
visit_edge o, "key"
|
153
166
|
end
|
154
167
|
|
155
168
|
def visit_Arel_Table(o)
|
@@ -167,47 +180,18 @@ module Arel # :nodoc: all
|
|
167
180
|
visit_edge o, "attribute"
|
168
181
|
end
|
169
182
|
|
170
|
-
def
|
183
|
+
def visit_Arel_Attributes_Attribute(o)
|
171
184
|
visit_edge o, "relation"
|
172
185
|
visit_edge o, "name"
|
173
186
|
end
|
174
|
-
alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute
|
175
|
-
alias :visit_Arel_Attributes_Float :visit_Arel_Attribute
|
176
|
-
alias :visit_Arel_Attributes_String :visit_Arel_Attribute
|
177
|
-
alias :visit_Arel_Attributes_Time :visit_Arel_Attribute
|
178
|
-
alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute
|
179
|
-
alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute
|
180
187
|
|
181
|
-
def
|
182
|
-
o.children.each_with_index do |
|
183
|
-
edge(i) { visit
|
188
|
+
def visit__children(o)
|
189
|
+
o.children.each_with_index do |child, i|
|
190
|
+
edge(i) { visit child }
|
184
191
|
end
|
185
192
|
end
|
186
|
-
alias :visit_Arel_Nodes_And :
|
187
|
-
|
188
|
-
def binary(o)
|
189
|
-
visit_edge o, "left"
|
190
|
-
visit_edge o, "right"
|
191
|
-
end
|
192
|
-
alias :visit_Arel_Nodes_As :binary
|
193
|
-
alias :visit_Arel_Nodes_Assignment :binary
|
194
|
-
alias :visit_Arel_Nodes_Between :binary
|
195
|
-
alias :visit_Arel_Nodes_Concat :binary
|
196
|
-
alias :visit_Arel_Nodes_DoesNotMatch :binary
|
197
|
-
alias :visit_Arel_Nodes_Equality :binary
|
198
|
-
alias :visit_Arel_Nodes_GreaterThan :binary
|
199
|
-
alias :visit_Arel_Nodes_GreaterThanOrEqual :binary
|
200
|
-
alias :visit_Arel_Nodes_In :binary
|
201
|
-
alias :visit_Arel_Nodes_JoinSource :binary
|
202
|
-
alias :visit_Arel_Nodes_LessThan :binary
|
203
|
-
alias :visit_Arel_Nodes_LessThanOrEqual :binary
|
204
|
-
alias :visit_Arel_Nodes_IsNotDistinctFrom :binary
|
205
|
-
alias :visit_Arel_Nodes_IsDistinctFrom :binary
|
206
|
-
alias :visit_Arel_Nodes_Matches :binary
|
207
|
-
alias :visit_Arel_Nodes_NotEqual :binary
|
208
|
-
alias :visit_Arel_Nodes_NotIn :binary
|
209
|
-
alias :visit_Arel_Nodes_Or :binary
|
210
|
-
alias :visit_Arel_Nodes_Over :binary
|
193
|
+
alias :visit_Arel_Nodes_And :visit__children
|
194
|
+
alias :visit_Arel_Nodes_With :visit__children
|
211
195
|
|
212
196
|
def visit_String(o)
|
213
197
|
@node_stack.last.fields << o
|
@@ -225,22 +209,22 @@ module Arel # :nodoc: all
|
|
225
209
|
alias :visit_Arel_Nodes_SqlLiteral :visit_String
|
226
210
|
|
227
211
|
def visit_Arel_Nodes_BindParam(o)
|
228
|
-
|
212
|
+
visit_edge(o, "value")
|
229
213
|
end
|
230
214
|
|
231
215
|
def visit_ActiveModel_Attribute(o)
|
232
|
-
|
216
|
+
visit_edge(o, "value_before_type_cast")
|
233
217
|
end
|
234
218
|
|
235
219
|
def visit_Hash(o)
|
236
220
|
o.each_with_index do |pair, i|
|
237
|
-
edge("pair_#{i}")
|
221
|
+
edge("pair_#{i}") { visit pair }
|
238
222
|
end
|
239
223
|
end
|
240
224
|
|
241
225
|
def visit_Array(o)
|
242
|
-
o.each_with_index do |
|
243
|
-
edge(i) { visit
|
226
|
+
o.each_with_index do |member, i|
|
227
|
+
edge(i) { visit member }
|
244
228
|
end
|
245
229
|
end
|
246
230
|
alias :visit_Set :visit_Array
|
@@ -249,6 +233,12 @@ module Arel # :nodoc: all
|
|
249
233
|
visit_edge(o, "values")
|
250
234
|
end
|
251
235
|
|
236
|
+
def visit_Arel_Nodes_Case(o)
|
237
|
+
visit_edge(o, "case")
|
238
|
+
visit_edge(o, "conditions")
|
239
|
+
visit_edge(o, "default")
|
240
|
+
end
|
241
|
+
|
252
242
|
def visit_edge(o, method)
|
253
243
|
edge(method) { visit o.send(method) }
|
254
244
|
end
|
data/lib/arel/visitors/mysql.rb
CHANGED
@@ -58,11 +58,17 @@ module Arel # :nodoc: all
|
|
58
58
|
infix_value o, collector, " NOT REGEXP "
|
59
59
|
end
|
60
60
|
|
61
|
+
# no-op
|
62
|
+
def visit_Arel_Nodes_NullsFirst(o, collector)
|
63
|
+
visit o.expr, collector
|
64
|
+
end
|
65
|
+
|
61
66
|
# In the simple case, MySQL allows us to place JOINs directly into the UPDATE
|
62
67
|
# query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
|
63
68
|
# these, we must use a subquery.
|
64
69
|
def prepare_update_statement(o)
|
65
|
-
if o.offset ||
|
70
|
+
if o.offset || has_group_by_and_having?(o) ||
|
71
|
+
has_join_sources?(o) && has_limit_or_offset_or_orders?(o)
|
66
72
|
super
|
67
73
|
else
|
68
74
|
o
|
@@ -70,7 +76,7 @@ module Arel # :nodoc: all
|
|
70
76
|
end
|
71
77
|
alias :prepare_delete_statement :prepare_update_statement
|
72
78
|
|
73
|
-
# MySQL
|
79
|
+
# MySQL doesn't automatically create a temporary table for use subquery, so we have
|
74
80
|
# to give it some prompting in the form of a subsubquery.
|
75
81
|
def build_subselect(key, o)
|
76
82
|
subselect = super
|
@@ -78,16 +78,6 @@ module Arel # :nodoc: all
|
|
78
78
|
visit o.right, collector
|
79
79
|
end
|
80
80
|
|
81
|
-
def visit_Arel_Nodes_NullsFirst(o, collector)
|
82
|
-
visit o.expr, collector
|
83
|
-
collector << " NULLS FIRST"
|
84
|
-
end
|
85
|
-
|
86
|
-
def visit_Arel_Nodes_NullsLast(o, collector)
|
87
|
-
visit o.expr, collector
|
88
|
-
collector << " NULLS LAST"
|
89
|
-
end
|
90
|
-
|
91
81
|
BIND_BLOCK = proc { |i| "$#{i}" }
|
92
82
|
private_constant :BIND_BLOCK
|
93
83
|
|
data/lib/arel/visitors/to_sql.rb
CHANGED
@@ -103,7 +103,7 @@ module Arel # :nodoc: all
|
|
103
103
|
row.each_with_index do |value, k|
|
104
104
|
collector << ", " unless k == 0
|
105
105
|
case value
|
106
|
-
when Nodes::SqlLiteral, Nodes::BindParam
|
106
|
+
when Nodes::SqlLiteral, Nodes::BindParam, ActiveModel::Attribute
|
107
107
|
collector = visit(value, collector)
|
108
108
|
else
|
109
109
|
collector << quote(value).to_s
|
@@ -135,6 +135,8 @@ module Arel # :nodoc: all
|
|
135
135
|
visit_Arel_Nodes_SelectOptions(o, collector)
|
136
136
|
end
|
137
137
|
|
138
|
+
# The Oracle enhanced adapter uses this private method,
|
139
|
+
# see https://github.com/rsim/oracle-enhanced/issues/2186
|
138
140
|
def visit_Arel_Nodes_SelectOptions(o, collector)
|
139
141
|
collector = maybe_visit o.limit, collector
|
140
142
|
collector = maybe_visit o.offset, collector
|
@@ -243,6 +245,13 @@ module Arel # :nodoc: all
|
|
243
245
|
collector << ")"
|
244
246
|
end
|
245
247
|
|
248
|
+
def visit_Arel_Nodes_Filter(o, collector)
|
249
|
+
visit o.left, collector
|
250
|
+
collector << " FILTER (WHERE "
|
251
|
+
visit o.right, collector
|
252
|
+
collector << ")"
|
253
|
+
end
|
254
|
+
|
246
255
|
def visit_Arel_Nodes_Rows(o, collector)
|
247
256
|
if o.expr
|
248
257
|
collector << "ROWS "
|
@@ -357,6 +366,17 @@ module Arel # :nodoc: all
|
|
357
366
|
visit(o.expr, collector) << " DESC"
|
358
367
|
end
|
359
368
|
|
369
|
+
# NullsFirst is available on all but MySQL, where it is redefined.
|
370
|
+
def visit_Arel_Nodes_NullsFirst(o, collector)
|
371
|
+
visit o.expr, collector
|
372
|
+
collector << " NULLS FIRST"
|
373
|
+
end
|
374
|
+
|
375
|
+
def visit_Arel_Nodes_NullsLast(o, collector)
|
376
|
+
visit o.expr, collector
|
377
|
+
collector << " NULLS LAST"
|
378
|
+
end
|
379
|
+
|
360
380
|
def visit_Arel_Nodes_Group(o, collector)
|
361
381
|
visit o.expr, collector
|
362
382
|
end
|
@@ -412,24 +432,48 @@ module Arel # :nodoc: all
|
|
412
432
|
end
|
413
433
|
|
414
434
|
def visit_Arel_Nodes_GreaterThanOrEqual(o, collector)
|
435
|
+
case unboundable?(o.right)
|
436
|
+
when 1
|
437
|
+
return collector << "1=0"
|
438
|
+
when -1
|
439
|
+
return collector << "1=1"
|
440
|
+
end
|
415
441
|
collector = visit o.left, collector
|
416
442
|
collector << " >= "
|
417
443
|
visit o.right, collector
|
418
444
|
end
|
419
445
|
|
420
446
|
def visit_Arel_Nodes_GreaterThan(o, collector)
|
447
|
+
case unboundable?(o.right)
|
448
|
+
when 1
|
449
|
+
return collector << "1=0"
|
450
|
+
when -1
|
451
|
+
return collector << "1=1"
|
452
|
+
end
|
421
453
|
collector = visit o.left, collector
|
422
454
|
collector << " > "
|
423
455
|
visit o.right, collector
|
424
456
|
end
|
425
457
|
|
426
458
|
def visit_Arel_Nodes_LessThanOrEqual(o, collector)
|
459
|
+
case unboundable?(o.right)
|
460
|
+
when 1
|
461
|
+
return collector << "1=1"
|
462
|
+
when -1
|
463
|
+
return collector << "1=0"
|
464
|
+
end
|
427
465
|
collector = visit o.left, collector
|
428
466
|
collector << " <= "
|
429
467
|
visit o.right, collector
|
430
468
|
end
|
431
469
|
|
432
470
|
def visit_Arel_Nodes_LessThan(o, collector)
|
471
|
+
case unboundable?(o.right)
|
472
|
+
when 1
|
473
|
+
return collector << "1=1"
|
474
|
+
when -1
|
475
|
+
return collector << "1=0"
|
476
|
+
end
|
433
477
|
collector = visit o.left, collector
|
434
478
|
collector << " < "
|
435
479
|
visit o.right, collector
|
@@ -585,7 +629,7 @@ module Arel # :nodoc: all
|
|
585
629
|
|
586
630
|
def visit_Arel_Nodes_Assignment(o, collector)
|
587
631
|
case o.right
|
588
|
-
when Arel::Nodes::Node, Arel::Attributes::Attribute
|
632
|
+
when Arel::Nodes::Node, Arel::Attributes::Attribute, ActiveModel::Attribute
|
589
633
|
collector = visit o.left, collector
|
590
634
|
collector << " = "
|
591
635
|
visit o.right, collector
|
@@ -695,6 +739,10 @@ module Arel # :nodoc: all
|
|
695
739
|
|
696
740
|
def bind_block; BIND_BLOCK; end
|
697
741
|
|
742
|
+
def visit_ActiveModel_Attribute(o, collector)
|
743
|
+
collector.add_bind(o, &bind_block)
|
744
|
+
end
|
745
|
+
|
698
746
|
def visit_Arel_Nodes_BindParam(o, collector)
|
699
747
|
collector.add_bind(o.value, &bind_block)
|
700
748
|
end
|
@@ -793,6 +841,10 @@ module Arel # :nodoc: all
|
|
793
841
|
o.limit || o.offset || !o.orders.empty?
|
794
842
|
end
|
795
843
|
|
844
|
+
def has_group_by_and_having?(o)
|
845
|
+
!o.groups.empty? && !o.havings.empty?
|
846
|
+
end
|
847
|
+
|
796
848
|
# The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
|
797
849
|
# on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
|
798
850
|
# an UPDATE statement, so in the MySQL visitor we redefine this to do that.
|
@@ -804,6 +856,8 @@ module Arel # :nodoc: all
|
|
804
856
|
stmt.orders = []
|
805
857
|
stmt.wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
|
806
858
|
stmt.relation = o.relation.left if has_join_sources?(o)
|
859
|
+
stmt.groups = o.groups unless o.groups.empty?
|
860
|
+
stmt.havings = o.havings unless o.havings.empty?
|
807
861
|
stmt
|
808
862
|
else
|
809
863
|
o
|
@@ -818,6 +872,8 @@ module Arel # :nodoc: all
|
|
818
872
|
core.froms = o.relation
|
819
873
|
core.wheres = o.wheres
|
820
874
|
core.projections = [key]
|
875
|
+
core.groups = o.groups unless o.groups.empty?
|
876
|
+
core.havings = o.havings unless o.havings.empty?
|
821
877
|
stmt.limit = o.limit
|
822
878
|
stmt.offset = o.offset
|
823
879
|
stmt.orders = o.orders
|
data/lib/arel.rb
CHANGED
@@ -7,6 +7,7 @@ require "arel/factory_methods"
|
|
7
7
|
|
8
8
|
require "arel/expressions"
|
9
9
|
require "arel/predications"
|
10
|
+
require "arel/filter_predications"
|
10
11
|
require "arel/window_predications"
|
11
12
|
require "arel/math"
|
12
13
|
require "arel/alias_predication"
|
@@ -29,7 +30,7 @@ module Arel
|
|
29
30
|
|
30
31
|
# Wrap a known-safe SQL string for passing to query methods, e.g.
|
31
32
|
#
|
32
|
-
# Post.order(Arel.sql("
|
33
|
+
# Post.order(Arel.sql("REPLACE(title, 'misc', 'zzzz') asc")).pluck(:id)
|
33
34
|
#
|
34
35
|
# Great caution should be taken to avoid SQL injection vulnerabilities.
|
35
36
|
# This method should not be used with unsafe values such as request
|
@@ -2,6 +2,6 @@
|
|
2
2
|
class <%= abstract_class_name %> < ApplicationRecord
|
3
3
|
self.abstract_class = true
|
4
4
|
|
5
|
-
connects_to database: { <%= ActiveRecord
|
5
|
+
connects_to database: { <%= ActiveRecord.writing_role %>: :<%= database -%> }
|
6
6
|
end
|
7
7
|
<% end -%>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<% module_namespacing do -%>
|
2
2
|
class <%= class_name %> < <%= parent_class_name.classify %>
|
3
3
|
<% attributes.select(&:reference?).each do |attribute| -%>
|
4
|
-
belongs_to :<%= attribute.name %><%=
|
4
|
+
belongs_to :<%= attribute.name %><%= ", polymorphic: true" if attribute.polymorphic? %>
|
5
5
|
<% end -%>
|
6
6
|
<% attributes.select(&:rich_text?).each do |attribute| -%>
|
7
7
|
has_rich_text :<%= attribute.name %>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<% module_namespacing do -%>
|
2
|
-
module <%= class_path.map(&:camelize).join(
|
2
|
+
module <%= class_path.map(&:camelize).join("::") %>
|
3
3
|
def self.table_name_prefix
|
4
|
-
|
4
|
+
"<%= namespaced? ? namespaced_class_path.join("_") : class_path.join("_") %>_"
|
5
5
|
end
|
6
6
|
end
|
7
7
|
<% end -%>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/active_record"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module Generators # :nodoc:
|
7
|
+
class MultiDbGenerator < ::Rails::Generators::Base # :nodoc:
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
def create_multi_db
|
11
|
+
filename = "multi_db.rb"
|
12
|
+
template filename, "config/initializers/#{filename}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Multi-db Configuration
|
2
|
+
#
|
3
|
+
# This file is used for configuration settings related to multiple databases.
|
4
|
+
#
|
5
|
+
# Enable Database Selector
|
6
|
+
#
|
7
|
+
# Inserts middleware to perform automatic connection switching.
|
8
|
+
# The `database_selector` hash is used to pass options to the DatabaseSelector
|
9
|
+
# middleware. The `delay` is used to determine how long to wait after a write
|
10
|
+
# to send a subsequent read to the primary.
|
11
|
+
#
|
12
|
+
# The `database_resolver` class is used by the middleware to determine which
|
13
|
+
# database is appropriate to use based on the time delay.
|
14
|
+
#
|
15
|
+
# The `database_resolver_context` class is used by the middleware to set
|
16
|
+
# timestamps for the last write to the primary. The resolver uses the context
|
17
|
+
# class timestamps to determine how long to wait before reading from the
|
18
|
+
# replica.
|
19
|
+
#
|
20
|
+
# By default Rails will store a last write timestamp in the session. The
|
21
|
+
# DatabaseSelector middleware is designed as such you can define your own
|
22
|
+
# strategy for connection switching and pass that into the middleware through
|
23
|
+
# these configuration options.
|
24
|
+
#
|
25
|
+
# Rails.application.configure do
|
26
|
+
# config.active_record.database_selector = { delay: 2.seconds }
|
27
|
+
# config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
|
28
|
+
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# Enable Shard Selector
|
32
|
+
#
|
33
|
+
# Inserts middleware to perform automatic shard swapping. The `shard_selector` hash
|
34
|
+
# can be used to pass options to the `ShardSelector` middleware. The `lock` option is
|
35
|
+
# used to determine whether shard swapping should be prohibited for the request.
|
36
|
+
#
|
37
|
+
# The `shard_resolver` option is used by the middleware to determine which shard
|
38
|
+
# to switch to. The application must provide a mechanism for finding the shard name
|
39
|
+
# in a proc. See guides for an example.
|
40
|
+
#
|
41
|
+
# Rails.application.configure do
|
42
|
+
# config.active_record.shard_selector = { lock: true }
|
43
|
+
# config.active_record.shard_resolver = ->(request) { Tenant.find_by!(host: request.host).shard }
|
44
|
+
# end
|