activerecord 3.2.19 → 5.0.0
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 +7 -0
- data/CHANGELOG.md +1715 -604
- data/MIT-LICENSE +2 -2
- data/README.rdoc +40 -45
- data/examples/performance.rb +33 -22
- data/examples/simple.rb +3 -4
- data/lib/active_record/aggregations.rb +76 -51
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +54 -40
- data/lib/active_record/associations/association.rb +76 -56
- data/lib/active_record/associations/association_scope.rb +125 -93
- data/lib/active_record/associations/belongs_to_association.rb +57 -28
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +120 -32
- data/lib/active_record/associations/builder/belongs_to.rb +115 -62
- data/lib/active_record/associations/builder/collection_association.rb +61 -53
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
- data/lib/active_record/associations/builder/has_many.rb +9 -65
- data/lib/active_record/associations/builder/has_one.rb +18 -52
- data/lib/active_record/associations/builder/singular_association.rb +18 -19
- data/lib/active_record/associations/collection_association.rb +268 -186
- data/lib/active_record/associations/collection_proxy.rb +1003 -63
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +81 -41
- data/lib/active_record/associations/has_many_through_association.rb +76 -55
- data/lib/active_record/associations/has_one_association.rb +51 -21
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
- data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
- data/lib/active_record/associations/join_dependency.rb +239 -155
- data/lib/active_record/associations/preloader/association.rb +97 -62
- data/lib/active_record/associations/preloader/collection_association.rb +2 -8
- data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +75 -33
- data/lib/active_record/associations/preloader.rb +111 -79
- data/lib/active_record/associations/singular_association.rb +35 -13
- data/lib/active_record/associations/through_association.rb +41 -19
- data/lib/active_record/associations.rb +727 -501
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +213 -0
- data/lib/active_record/attribute_assignment.rb +32 -162
- data/lib/active_record/attribute_decorators.rb +67 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -61
- data/lib/active_record/attribute_methods/primary_key.rb +50 -36
- data/lib/active_record/attribute_methods/query.rb +7 -6
- data/lib/active_record/attribute_methods/read.rb +56 -117
- data/lib/active_record/attribute_methods/serialization.rb +43 -96
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
- data/lib/active_record/attribute_methods/write.rb +34 -45
- data/lib/active_record/attribute_methods.rb +333 -144
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +108 -0
- data/lib/active_record/attribute_set.rb +108 -0
- data/lib/active_record/attributes.rb +265 -0
- data/lib/active_record/autosave_association.rb +285 -223
- data/lib/active_record/base.rb +95 -490
- data/lib/active_record/callbacks.rb +95 -61
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +28 -19
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
- data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
- data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
- data/lib/active_record/connection_adapters/column.rb +30 -259
- data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
- data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
- data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +155 -0
- data/lib/active_record/core.rb +561 -0
- data/lib/active_record/counter_cache.rb +146 -105
- data/lib/active_record/dynamic_matchers.rb +101 -64
- data/lib/active_record/enum.rb +234 -0
- data/lib/active_record/errors.rb +153 -56
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +10 -6
- data/lib/active_record/fixture_set/file.rb +77 -0
- data/lib/active_record/fixtures.rb +355 -232
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +144 -79
- data/lib/active_record/integration.rb +66 -13
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +9 -1
- data/lib/active_record/locking/optimistic.rb +77 -56
- data/lib/active_record/locking/pessimistic.rb +6 -6
- data/lib/active_record/log_subscriber.rb +53 -28
- data/lib/active_record/migration/command_recorder.rb +166 -33
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +792 -264
- data/lib/active_record/model_schema.rb +192 -130
- data/lib/active_record/nested_attributes.rb +238 -145
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +89 -0
- data/lib/active_record/persistence.rb +357 -157
- data/lib/active_record/query_cache.rb +22 -43
- data/lib/active_record/querying.rb +34 -23
- data/lib/active_record/railtie.rb +88 -48
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +5 -4
- data/lib/active_record/railties/databases.rake +170 -422
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -5
- data/lib/active_record/reflection.rb +715 -189
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +203 -50
- data/lib/active_record/relation/calculations.rb +203 -194
- data/lib/active_record/relation/delegation.rb +103 -25
- data/lib/active_record/relation/finder_methods.rb +457 -261
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +167 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/predicate_builder.rb +153 -48
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +1019 -194
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +46 -150
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +450 -245
- data/lib/active_record/result.rb +104 -12
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +120 -94
- data/lib/active_record/schema.rb +28 -18
- data/lib/active_record/schema_dumper.rb +141 -74
- data/lib/active_record/schema_migration.rb +50 -0
- data/lib/active_record/scoping/default.rb +64 -57
- data/lib/active_record/scoping/named.rb +93 -108
- data/lib/active_record/scoping.rb +73 -121
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +7 -5
- data/lib/active_record/statement_cache.rb +113 -0
- data/lib/active_record/store.rb +173 -15
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +313 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
- data/lib/active_record/timestamp.rb +42 -24
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +233 -105
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +7 -0
- data/lib/active_record/type/date_time.rb +7 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +63 -0
- data/lib/active_record/type/time.rb +20 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type.rb +72 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +33 -18
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +66 -0
- data/lib/active_record/validations/uniqueness.rb +128 -68
- data/lib/active_record/validations.rb +48 -40
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +71 -47
- data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
- data/lib/rails/generators/active_record/migration.rb +18 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +188 -134
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,23 +1,26 @@
|
|
1
|
-
require 'thread'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
# See ActiveRecord::Transactions::ClassMethods for documentation.
|
5
3
|
module Transactions
|
6
4
|
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
|
9
|
-
end
|
5
|
+
#:nodoc:
|
6
|
+
ACTIONS = [:create, :destroy, :update]
|
10
7
|
|
11
8
|
included do
|
12
|
-
define_callbacks :commit, :rollback,
|
9
|
+
define_callbacks :commit, :rollback,
|
10
|
+
:before_commit,
|
11
|
+
:before_commit_without_transaction_enrollment,
|
12
|
+
:commit_without_transaction_enrollment,
|
13
|
+
:rollback_without_transaction_enrollment,
|
14
|
+
terminator: deprecated_false_terminator,
|
15
|
+
scope: [:kind, :name]
|
13
16
|
end
|
14
17
|
|
15
18
|
# = Active Record Transactions
|
16
19
|
#
|
17
|
-
# Transactions are protective blocks where SQL statements are only permanent
|
20
|
+
# \Transactions are protective blocks where SQL statements are only permanent
|
18
21
|
# if they can all succeed as one atomic action. The classic example is a
|
19
22
|
# transfer between two accounts where you can only have a deposit if the
|
20
|
-
# withdrawal succeeded and vice versa. Transactions enforce the integrity of
|
23
|
+
# withdrawal succeeded and vice versa. \Transactions enforce the integrity of
|
21
24
|
# the database and guard the data against program errors or database
|
22
25
|
# break-downs. So basically you should use transaction blocks whenever you
|
23
26
|
# have a number of statements that must be executed together or not at all.
|
@@ -37,20 +40,20 @@ module ActiveRecord
|
|
37
40
|
#
|
38
41
|
# == Different Active Record classes in a single transaction
|
39
42
|
#
|
40
|
-
# Though the transaction class method is called on some Active Record class,
|
43
|
+
# Though the #transaction class method is called on some Active Record class,
|
41
44
|
# the objects within the transaction block need not all be instances of
|
42
45
|
# that class. This is because transactions are per-database connection, not
|
43
46
|
# per-model.
|
44
47
|
#
|
45
48
|
# In this example a +balance+ record is transactionally saved even
|
46
|
-
# though
|
49
|
+
# though #transaction is called on the +Account+ class:
|
47
50
|
#
|
48
51
|
# Account.transaction do
|
49
52
|
# balance.save!
|
50
53
|
# account.save!
|
51
54
|
# end
|
52
55
|
#
|
53
|
-
# The
|
56
|
+
# The #transaction method is also available as a model instance method.
|
54
57
|
# For example, you can also do this:
|
55
58
|
#
|
56
59
|
# balance.transaction do
|
@@ -77,7 +80,8 @@ module ActiveRecord
|
|
77
80
|
#
|
78
81
|
# == +save+ and +destroy+ are automatically wrapped in a transaction
|
79
82
|
#
|
80
|
-
# Both
|
83
|
+
# Both {#save}[rdoc-ref:Persistence#save] and
|
84
|
+
# {#destroy}[rdoc-ref:Persistence#destroy] come wrapped in a transaction that ensures
|
81
85
|
# that whatever you do in validations or callbacks will happen under its
|
82
86
|
# protected cover. So you can use validations to check for values that
|
83
87
|
# the transaction depends on or you can raise exceptions in the callbacks
|
@@ -86,7 +90,7 @@ module ActiveRecord
|
|
86
90
|
# As a consequence changes to the database are not seen outside your connection
|
87
91
|
# until the operation is complete. For example, if you try to update the index
|
88
92
|
# of a search engine in +after_save+ the indexer won't see the updated record.
|
89
|
-
# The
|
93
|
+
# The #after_commit callback is the only one that is triggered once the update
|
90
94
|
# is committed. See below.
|
91
95
|
#
|
92
96
|
# == Exception handling and rolling back
|
@@ -95,11 +99,11 @@ module ActiveRecord
|
|
95
99
|
# be propagated (after triggering the ROLLBACK), so you should be ready to
|
96
100
|
# catch those in your application code.
|
97
101
|
#
|
98
|
-
# One exception is the
|
102
|
+
# One exception is the ActiveRecord::Rollback exception, which will trigger
|
99
103
|
# a ROLLBACK when raised, but not be re-raised by the transaction block.
|
100
104
|
#
|
101
|
-
# *Warning*: one should not catch
|
102
|
-
# inside a transaction block.
|
105
|
+
# *Warning*: one should not catch ActiveRecord::StatementInvalid exceptions
|
106
|
+
# inside a transaction block. ActiveRecord::StatementInvalid exceptions indicate that an
|
103
107
|
# error occurred at the database level, for example when a unique constraint
|
104
108
|
# is violated. On some database systems, such as PostgreSQL, database errors
|
105
109
|
# inside a transaction cause the entire transaction to become unusable
|
@@ -108,10 +112,10 @@ module ActiveRecord
|
|
108
112
|
#
|
109
113
|
# # Suppose that we have a Number model with a unique column called 'i'.
|
110
114
|
# Number.transaction do
|
111
|
-
# Number.create(:
|
115
|
+
# Number.create(i: 0)
|
112
116
|
# begin
|
113
117
|
# # This will raise a unique constraint error...
|
114
|
-
# Number.create(:
|
118
|
+
# Number.create(i: 0)
|
115
119
|
# rescue ActiveRecord::StatementInvalid
|
116
120
|
# # ...which we ignore.
|
117
121
|
# end
|
@@ -119,68 +123,68 @@ module ActiveRecord
|
|
119
123
|
# # On PostgreSQL, the transaction is now unusable. The following
|
120
124
|
# # statement will cause a PostgreSQL error, even though the unique
|
121
125
|
# # constraint is no longer violated:
|
122
|
-
# Number.create(:
|
126
|
+
# Number.create(i: 1)
|
123
127
|
# # => "PGError: ERROR: current transaction is aborted, commands
|
124
128
|
# # ignored until end of transaction block"
|
125
129
|
# end
|
126
130
|
#
|
127
131
|
# One should restart the entire transaction if an
|
128
|
-
#
|
132
|
+
# ActiveRecord::StatementInvalid occurred.
|
129
133
|
#
|
130
134
|
# == Nested transactions
|
131
135
|
#
|
132
|
-
#
|
136
|
+
# #transaction calls can be nested. By default, this makes all database
|
133
137
|
# statements in the nested transaction block become part of the parent
|
134
138
|
# transaction. For example, the following behavior may be surprising:
|
135
139
|
#
|
136
140
|
# User.transaction do
|
137
|
-
# User.create(:
|
141
|
+
# User.create(username: 'Kotori')
|
138
142
|
# User.transaction do
|
139
|
-
# User.create(:
|
143
|
+
# User.create(username: 'Nemu')
|
140
144
|
# raise ActiveRecord::Rollback
|
141
145
|
# end
|
142
146
|
# end
|
143
147
|
#
|
144
|
-
# creates both "Kotori" and "Nemu". Reason is the
|
148
|
+
# creates both "Kotori" and "Nemu". Reason is the ActiveRecord::Rollback
|
145
149
|
# exception in the nested block does not issue a ROLLBACK. Since these exceptions
|
146
150
|
# are captured in transaction blocks, the parent block does not see it and the
|
147
151
|
# real transaction is committed.
|
148
152
|
#
|
149
153
|
# In order to get a ROLLBACK for the nested transaction you may ask for a real
|
150
|
-
# sub-transaction by passing <tt
|
154
|
+
# sub-transaction by passing <tt>requires_new: true</tt>. If anything goes wrong,
|
151
155
|
# the database rolls back to the beginning of the sub-transaction without rolling
|
152
156
|
# back the parent transaction. If we add it to the previous example:
|
153
157
|
#
|
154
158
|
# User.transaction do
|
155
|
-
# User.create(:
|
156
|
-
# User.transaction(:
|
157
|
-
# User.create(:
|
159
|
+
# User.create(username: 'Kotori')
|
160
|
+
# User.transaction(requires_new: true) do
|
161
|
+
# User.create(username: 'Nemu')
|
158
162
|
# raise ActiveRecord::Rollback
|
159
163
|
# end
|
160
164
|
# end
|
161
165
|
#
|
162
|
-
# only "Kotori" is created.
|
166
|
+
# only "Kotori" is created. This works on MySQL and PostgreSQL. SQLite3 version >= '3.6.8' also supports it.
|
163
167
|
#
|
164
168
|
# Most databases don't support true nested transactions. At the time of
|
165
169
|
# writing, the only database that we're aware of that supports true nested
|
166
170
|
# transactions, is MS-SQL. Because of this, Active Record emulates nested
|
167
171
|
# transactions by using savepoints on MySQL and PostgreSQL. See
|
168
|
-
# http://dev.mysql.com/doc/refman/5.
|
172
|
+
# http://dev.mysql.com/doc/refman/5.7/en/savepoint.html
|
169
173
|
# for more information about savepoints.
|
170
174
|
#
|
171
|
-
# === Callbacks
|
175
|
+
# === \Callbacks
|
172
176
|
#
|
173
177
|
# There are two types of callbacks associated with committing and rolling back transactions:
|
174
|
-
#
|
178
|
+
# #after_commit and #after_rollback.
|
175
179
|
#
|
176
|
-
#
|
177
|
-
# transaction immediately after the transaction is committed.
|
180
|
+
# #after_commit callbacks are called on every record saved or destroyed within a
|
181
|
+
# transaction immediately after the transaction is committed. #after_rollback callbacks
|
178
182
|
# are called on every record saved or destroyed within a transaction immediately after the
|
179
183
|
# transaction or savepoint is rolled back.
|
180
184
|
#
|
181
185
|
# These callbacks are useful for interacting with other systems since you will be guaranteed
|
182
186
|
# that the callback is only executed when the database is in a permanent state. For example,
|
183
|
-
#
|
187
|
+
# #after_commit is a good spot to put in a hook to clearing a cache since clearing it from
|
184
188
|
# within a transaction could trigger the cache to be regenerated before the database is updated.
|
185
189
|
#
|
186
190
|
# === Caveats
|
@@ -194,55 +198,111 @@ module ActiveRecord
|
|
194
198
|
# automatically released. The following example demonstrates the problem:
|
195
199
|
#
|
196
200
|
# Model.connection.transaction do # BEGIN
|
197
|
-
# Model.connection.transaction(:
|
201
|
+
# Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
|
198
202
|
# Model.connection.create_table(...) # active_record_1 now automatically released
|
199
|
-
# end # RELEASE
|
203
|
+
# end # RELEASE SAVEPOINT active_record_1
|
200
204
|
# # ^^^^ BOOM! database error!
|
201
205
|
# end
|
202
206
|
#
|
203
207
|
# Note that "TRUNCATE" is also a MySQL DDL statement!
|
204
208
|
module ClassMethods
|
205
|
-
# See
|
209
|
+
# See the ConnectionAdapters::DatabaseStatements#transaction API docs.
|
206
210
|
def transaction(options = {}, &block)
|
207
|
-
# See the ConnectionAdapters::DatabaseStatements#transaction API docs.
|
208
211
|
connection.transaction(options, &block)
|
209
212
|
end
|
210
213
|
|
214
|
+
def before_commit(*args, &block) # :nodoc:
|
215
|
+
set_options_for_callbacks!(args)
|
216
|
+
set_callback(:before_commit, :before, *args, &block)
|
217
|
+
end
|
218
|
+
|
211
219
|
# This callback is called after a record has been created, updated, or destroyed.
|
212
220
|
#
|
213
221
|
# You can specify that the callback should only be fired by a certain action with
|
214
222
|
# the +:on+ option:
|
215
223
|
#
|
216
|
-
# after_commit :do_foo, :
|
217
|
-
# after_commit :do_bar, :
|
218
|
-
# after_commit :do_baz, :
|
224
|
+
# after_commit :do_foo, on: :create
|
225
|
+
# after_commit :do_bar, on: :update
|
226
|
+
# after_commit :do_baz, on: :destroy
|
219
227
|
#
|
220
|
-
#
|
228
|
+
# after_commit :do_foo_bar, on: [:create, :update]
|
229
|
+
# after_commit :do_bar_baz, on: [:update, :destroy]
|
221
230
|
#
|
222
|
-
# after_commit :do_zoo, :if => :persisted?
|
223
|
-
#
|
224
|
-
# Note that transactional fixtures do not play well with this feature. Please
|
225
|
-
# use the +test_after_commit+ gem to have these hooks fired in tests.
|
226
231
|
def after_commit(*args, &block)
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
+
set_options_for_callbacks!(args)
|
233
|
+
set_callback(:commit, :after, *args, &block)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Shortcut for <tt>after_commit :hook, on: :create</tt>.
|
237
|
+
def after_create_commit(*args, &block)
|
238
|
+
set_options_for_callbacks!(args, on: :create)
|
239
|
+
set_callback(:commit, :after, *args, &block)
|
240
|
+
end
|
241
|
+
|
242
|
+
# Shortcut for <tt>after_commit :hook, on: :update</tt>.
|
243
|
+
def after_update_commit(*args, &block)
|
244
|
+
set_options_for_callbacks!(args, on: :update)
|
245
|
+
set_callback(:commit, :after, *args, &block)
|
246
|
+
end
|
247
|
+
|
248
|
+
# Shortcut for <tt>after_commit :hook, on: :destroy</tt>.
|
249
|
+
def after_destroy_commit(*args, &block)
|
250
|
+
set_options_for_callbacks!(args, on: :destroy)
|
232
251
|
set_callback(:commit, :after, *args, &block)
|
233
252
|
end
|
234
253
|
|
235
254
|
# This callback is called after a create, update, or destroy are rolled back.
|
236
255
|
#
|
237
|
-
# Please check the documentation of
|
256
|
+
# Please check the documentation of #after_commit for options.
|
238
257
|
def after_rollback(*args, &block)
|
239
|
-
|
240
|
-
if options.is_a?(Hash) && options[:on]
|
241
|
-
options[:if] = Array.wrap(options[:if])
|
242
|
-
options[:if] << "transaction_include_action?(:#{options[:on]})"
|
243
|
-
end
|
258
|
+
set_options_for_callbacks!(args)
|
244
259
|
set_callback(:rollback, :after, *args, &block)
|
245
260
|
end
|
261
|
+
|
262
|
+
def before_commit_without_transaction_enrollment(*args, &block) # :nodoc:
|
263
|
+
set_options_for_callbacks!(args)
|
264
|
+
set_callback(:before_commit_without_transaction_enrollment, :before, *args, &block)
|
265
|
+
end
|
266
|
+
|
267
|
+
def after_commit_without_transaction_enrollment(*args, &block) # :nodoc:
|
268
|
+
set_options_for_callbacks!(args)
|
269
|
+
set_callback(:commit_without_transaction_enrollment, :after, *args, &block)
|
270
|
+
end
|
271
|
+
|
272
|
+
def after_rollback_without_transaction_enrollment(*args, &block) # :nodoc:
|
273
|
+
set_options_for_callbacks!(args)
|
274
|
+
set_callback(:rollback_without_transaction_enrollment, :after, *args, &block)
|
275
|
+
end
|
276
|
+
|
277
|
+
def raise_in_transactional_callbacks
|
278
|
+
ActiveSupport::Deprecation.warn('ActiveRecord::Base.raise_in_transactional_callbacks is deprecated and will be removed without replacement.')
|
279
|
+
true
|
280
|
+
end
|
281
|
+
|
282
|
+
def raise_in_transactional_callbacks=(value)
|
283
|
+
ActiveSupport::Deprecation.warn('ActiveRecord::Base.raise_in_transactional_callbacks= is deprecated, has no effect and will be removed without replacement.')
|
284
|
+
value
|
285
|
+
end
|
286
|
+
|
287
|
+
private
|
288
|
+
|
289
|
+
def set_options_for_callbacks!(args, enforced_options = {})
|
290
|
+
options = args.extract_options!.merge!(enforced_options)
|
291
|
+
args << options
|
292
|
+
|
293
|
+
if options[:on]
|
294
|
+
fire_on = Array(options[:on])
|
295
|
+
assert_valid_transaction_action(fire_on)
|
296
|
+
options[:if] = Array(options[:if])
|
297
|
+
options[:if] << "transaction_include_any_action?(#{fire_on})"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def assert_valid_transaction_action(actions)
|
302
|
+
if (actions - ACTIONS).any?
|
303
|
+
raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}"
|
304
|
+
end
|
305
|
+
end
|
246
306
|
end
|
247
307
|
|
248
308
|
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
|
@@ -264,40 +324,61 @@ module ActiveRecord
|
|
264
324
|
with_transaction_returning_status { super }
|
265
325
|
end
|
266
326
|
|
327
|
+
def touch(*) #:nodoc:
|
328
|
+
with_transaction_returning_status { super }
|
329
|
+
end
|
330
|
+
|
267
331
|
# Reset id and @new_record if the transaction rolls back.
|
268
332
|
def rollback_active_record_state!
|
269
333
|
remember_transaction_record_state
|
270
334
|
yield
|
271
335
|
rescue Exception
|
272
|
-
IdentityMap.remove(self) if IdentityMap.enabled?
|
273
336
|
restore_transaction_record_state
|
274
337
|
raise
|
275
338
|
ensure
|
276
339
|
clear_transaction_record_state
|
277
340
|
end
|
278
341
|
|
279
|
-
|
280
|
-
|
281
|
-
|
342
|
+
def before_committed! # :nodoc:
|
343
|
+
_run_before_commit_without_transaction_enrollment_callbacks
|
344
|
+
_run_before_commit_callbacks
|
345
|
+
end
|
346
|
+
|
347
|
+
# Call the #after_commit callbacks.
|
348
|
+
#
|
349
|
+
# Ensure that it is not called if the object was never persisted (failed create),
|
350
|
+
# but call it after the commit of a destroyed object.
|
351
|
+
def committed!(should_run_callbacks: true) #:nodoc:
|
352
|
+
if should_run_callbacks && destroyed? || persisted?
|
353
|
+
_run_commit_without_transaction_enrollment_callbacks
|
354
|
+
_run_commit_callbacks
|
355
|
+
end
|
282
356
|
ensure
|
283
|
-
|
357
|
+
force_clear_transaction_record_state
|
284
358
|
end
|
285
359
|
|
286
|
-
# Call the
|
360
|
+
# Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
|
287
361
|
# state should be rolled back to the beginning or just to the last savepoint.
|
288
|
-
def rolledback!(force_restore_state
|
289
|
-
|
362
|
+
def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
|
363
|
+
if should_run_callbacks
|
364
|
+
_run_rollback_callbacks
|
365
|
+
_run_rollback_without_transaction_enrollment_callbacks
|
366
|
+
end
|
290
367
|
ensure
|
291
|
-
IdentityMap.remove(self) if IdentityMap.enabled?
|
292
368
|
restore_transaction_record_state(force_restore_state)
|
369
|
+
clear_transaction_record_state
|
293
370
|
end
|
294
371
|
|
295
|
-
# Add the record to the current transaction so that the
|
372
|
+
# Add the record to the current transaction so that the #after_rollback and #after_commit callbacks
|
296
373
|
# can be called.
|
297
374
|
def add_to_transaction
|
298
|
-
if
|
299
|
-
|
375
|
+
if has_transactional_callbacks?
|
376
|
+
self.class.connection.add_transaction_record(self)
|
377
|
+
else
|
378
|
+
sync_with_transaction_state
|
379
|
+
set_transaction_state(self.class.connection.transaction_state)
|
300
380
|
end
|
381
|
+
remember_transaction_record_state
|
301
382
|
end
|
302
383
|
|
303
384
|
# Executes +method+ within a transaction and captures its return value as a
|
@@ -310,71 +391,118 @@ module ActiveRecord
|
|
310
391
|
status = nil
|
311
392
|
self.class.transaction do
|
312
393
|
add_to_transaction
|
313
|
-
|
394
|
+
begin
|
395
|
+
status = yield
|
396
|
+
rescue ActiveRecord::Rollback
|
397
|
+
clear_transaction_record_state
|
398
|
+
status = nil
|
399
|
+
end
|
400
|
+
|
314
401
|
raise ActiveRecord::Rollback unless status
|
315
402
|
end
|
316
403
|
status
|
404
|
+
ensure
|
405
|
+
if @transaction_state && @transaction_state.committed?
|
406
|
+
clear_transaction_record_state
|
407
|
+
end
|
317
408
|
end
|
318
409
|
|
319
410
|
protected
|
320
411
|
|
321
412
|
# Save the new record state and id of a record so it can be restored later if a transaction fails.
|
322
413
|
def remember_transaction_record_state #:nodoc:
|
323
|
-
@_start_transaction_state
|
324
|
-
@_start_transaction_state
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
@_start_transaction_state[:destroyed] = @destroyed
|
330
|
-
end
|
414
|
+
@_start_transaction_state[:id] = id
|
415
|
+
@_start_transaction_state.reverse_merge!(
|
416
|
+
new_record: @new_record,
|
417
|
+
destroyed: @destroyed,
|
418
|
+
frozen?: frozen?,
|
419
|
+
)
|
331
420
|
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) + 1
|
332
|
-
@_start_transaction_state[:frozen?] = @attributes.frozen?
|
333
421
|
end
|
334
422
|
|
335
423
|
# Clear the new record state and id of a record.
|
336
424
|
def clear_transaction_record_state #:nodoc:
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
425
|
+
@_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
|
426
|
+
force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
|
427
|
+
end
|
428
|
+
|
429
|
+
# Force to clear the transaction record state.
|
430
|
+
def force_clear_transaction_record_state #:nodoc:
|
431
|
+
@_start_transaction_state.clear
|
341
432
|
end
|
342
433
|
|
343
434
|
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
|
344
435
|
def restore_transaction_record_state(force = false) #:nodoc:
|
345
|
-
|
346
|
-
|
347
|
-
if
|
348
|
-
restore_state =
|
349
|
-
|
350
|
-
@attributes = @attributes.dup if @attributes.frozen?
|
436
|
+
unless @_start_transaction_state.empty?
|
437
|
+
transaction_level = (@_start_transaction_state[:level] || 0) - 1
|
438
|
+
if transaction_level < 1 || force
|
439
|
+
restore_state = @_start_transaction_state
|
440
|
+
thaw
|
351
441
|
@new_record = restore_state[:new_record]
|
352
442
|
@destroyed = restore_state[:destroyed]
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
@attributes.delete(self.class.primary_key)
|
357
|
-
@attributes_cache.delete(self.class.primary_key)
|
443
|
+
pk = self.class.primary_key
|
444
|
+
if pk && read_attribute(pk) != restore_state[:id]
|
445
|
+
write_attribute(pk, restore_state[:id])
|
358
446
|
end
|
359
|
-
|
447
|
+
freeze if restore_state[:frozen?]
|
360
448
|
end
|
361
449
|
end
|
362
450
|
end
|
363
451
|
|
364
452
|
# Determine if a record was created or destroyed in a transaction. State should be one of :new_record or :destroyed.
|
365
453
|
def transaction_record_state(state) #:nodoc:
|
366
|
-
@_start_transaction_state[state]
|
454
|
+
@_start_transaction_state[state]
|
367
455
|
end
|
368
456
|
|
369
457
|
# Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
|
370
|
-
def
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
458
|
+
def transaction_include_any_action?(actions) #:nodoc:
|
459
|
+
actions.any? do |action|
|
460
|
+
case action
|
461
|
+
when :create
|
462
|
+
transaction_record_state(:new_record)
|
463
|
+
when :destroy
|
464
|
+
destroyed?
|
465
|
+
when :update
|
466
|
+
!(transaction_record_state(:new_record) || destroyed?)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
private
|
472
|
+
|
473
|
+
def set_transaction_state(state) # :nodoc:
|
474
|
+
@transaction_state = state
|
475
|
+
end
|
476
|
+
|
477
|
+
def has_transactional_callbacks? # :nodoc:
|
478
|
+
!_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
|
479
|
+
end
|
480
|
+
|
481
|
+
# Updates the attributes on this particular Active Record object so that
|
482
|
+
# if it's associated with a transaction, then the state of the Active Record
|
483
|
+
# object will be updated to reflect the current state of the transaction
|
484
|
+
#
|
485
|
+
# The +@transaction_state+ variable stores the states of the associated
|
486
|
+
# transaction. This relies on the fact that a transaction can only be in
|
487
|
+
# one rollback or commit (otherwise a list of states would be required)
|
488
|
+
# Each Active Record object inside of a transaction carries that transaction's
|
489
|
+
# TransactionState.
|
490
|
+
#
|
491
|
+
# This method checks to see if the ActiveRecord object's state reflects
|
492
|
+
# the TransactionState, and rolls back or commits the Active Record object
|
493
|
+
# as appropriate.
|
494
|
+
#
|
495
|
+
# Since Active Record objects can be inside multiple transactions, this
|
496
|
+
# method recursively goes through the parent of the TransactionState and
|
497
|
+
# checks if the Active Record object reflects the state of the object.
|
498
|
+
def sync_with_transaction_state
|
499
|
+
update_attributes_from_transaction_state(@transaction_state)
|
500
|
+
end
|
501
|
+
|
502
|
+
def update_attributes_from_transaction_state(transaction_state)
|
503
|
+
if transaction_state && transaction_state.finalized?
|
504
|
+
restore_transaction_record_state if transaction_state.rolledback?
|
505
|
+
clear_transaction_record_state
|
378
506
|
end
|
379
507
|
end
|
380
508
|
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'active_model/type/registry'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# :stopdoc:
|
5
|
+
module Type
|
6
|
+
class AdapterSpecificRegistry < ActiveModel::Type::Registry
|
7
|
+
def add_modifier(options, klass, **args)
|
8
|
+
registrations << DecorationRegistration.new(options, klass, **args)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def registration_klass
|
14
|
+
Registration
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_registration(symbol, *args)
|
18
|
+
registrations
|
19
|
+
.select { |registration| registration.matches?(symbol, *args) }
|
20
|
+
.max
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Registration
|
25
|
+
def initialize(name, block, adapter: nil, override: nil)
|
26
|
+
@name = name
|
27
|
+
@block = block
|
28
|
+
@adapter = adapter
|
29
|
+
@override = override
|
30
|
+
end
|
31
|
+
|
32
|
+
def call(_registry, *args, adapter: nil, **kwargs)
|
33
|
+
if kwargs.any? # https://bugs.ruby-lang.org/issues/10856
|
34
|
+
block.call(*args, **kwargs)
|
35
|
+
else
|
36
|
+
block.call(*args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def matches?(type_name, *args, **kwargs)
|
41
|
+
type_name == name && matches_adapter?(**kwargs)
|
42
|
+
end
|
43
|
+
|
44
|
+
def <=>(other)
|
45
|
+
if conflicts_with?(other)
|
46
|
+
raise TypeConflictError.new("Type #{name} was registered for all
|
47
|
+
adapters, but shadows a native type with
|
48
|
+
the same name for #{other.adapter}".squish)
|
49
|
+
end
|
50
|
+
priority <=> other.priority
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
attr_reader :name, :block, :adapter, :override
|
56
|
+
|
57
|
+
def priority
|
58
|
+
result = 0
|
59
|
+
if adapter
|
60
|
+
result |= 1
|
61
|
+
end
|
62
|
+
if override
|
63
|
+
result |= 2
|
64
|
+
end
|
65
|
+
result
|
66
|
+
end
|
67
|
+
|
68
|
+
def priority_except_adapter
|
69
|
+
priority & 0b111111100
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def matches_adapter?(adapter: nil, **)
|
75
|
+
(self.adapter.nil? || adapter == self.adapter)
|
76
|
+
end
|
77
|
+
|
78
|
+
def conflicts_with?(other)
|
79
|
+
same_priority_except_adapter?(other) &&
|
80
|
+
has_adapter_conflict?(other)
|
81
|
+
end
|
82
|
+
|
83
|
+
def same_priority_except_adapter?(other)
|
84
|
+
priority_except_adapter == other.priority_except_adapter
|
85
|
+
end
|
86
|
+
|
87
|
+
def has_adapter_conflict?(other)
|
88
|
+
(override.nil? && other.adapter) ||
|
89
|
+
(adapter && other.override.nil?)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class DecorationRegistration < Registration
|
94
|
+
def initialize(options, klass, adapter: nil)
|
95
|
+
@options = options
|
96
|
+
@klass = klass
|
97
|
+
@adapter = adapter
|
98
|
+
end
|
99
|
+
|
100
|
+
def call(registry, *args, **kwargs)
|
101
|
+
subtype = registry.lookup(*args, **kwargs.except(*options.keys))
|
102
|
+
klass.new(subtype)
|
103
|
+
end
|
104
|
+
|
105
|
+
def matches?(*args, **kwargs)
|
106
|
+
matches_adapter?(**kwargs) && matches_options?(**kwargs)
|
107
|
+
end
|
108
|
+
|
109
|
+
def priority
|
110
|
+
super | 4
|
111
|
+
end
|
112
|
+
|
113
|
+
protected
|
114
|
+
|
115
|
+
attr_reader :options, :klass
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def matches_options?(**kwargs)
|
120
|
+
options.all? do |key, value|
|
121
|
+
kwargs[key] == value
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class TypeConflictError < StandardError
|
128
|
+
end
|
129
|
+
# :startdoc:
|
130
|
+
end
|