activerecord 6.0.1 → 6.1.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 +4 -4
- data/CHANGELOG.md +843 -626
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -3
- data/lib/active_record/aggregations.rb +1 -2
- data/lib/active_record/association_relation.rb +18 -17
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +49 -37
- data/lib/active_record/associations/association_scope.rb +17 -15
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +9 -3
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +25 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +73 -42
- data/lib/active_record/associations/preloader/association.rb +51 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/preloader.rb +12 -7
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +115 -12
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +32 -8
- data/lib/active_record/autosave_association.rb +56 -41
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +190 -136
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +82 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
- data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
- data/lib/active_record/connection_adapters/abstract_adapter.rb +60 -73
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +28 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -56
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +77 -57
- data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +36 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +57 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +210 -87
- data/lib/active_record/core.rb +229 -65
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- data/lib/active_record/database_configurations.rb +124 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +40 -16
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +54 -11
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +38 -9
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +16 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +22 -17
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +27 -9
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +70 -20
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +114 -84
- data/lib/active_record/model_schema.rb +117 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/databases.rake +267 -93
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/calculations.rb +102 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +45 -16
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +55 -35
- data/lib/active_record/relation/query_methods.rb +335 -187
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +104 -58
- data/lib/active_record/relation.rb +108 -68
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +0 -1
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +3 -3
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -36
- data/lib/active_record/tasks/database_tasks.rb +139 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +38 -16
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +21 -70
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +5 -9
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +26 -26
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -12,26 +12,24 @@ module ActiveRecord
|
|
12
12
|
delegate :connection, :establish_connection, :clear_active_connections!,
|
13
13
|
to: ActiveRecord::Base
|
14
14
|
|
15
|
-
def
|
16
|
-
|
15
|
+
def self.using_database_configurations?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(db_config)
|
20
|
+
@db_config = db_config
|
21
|
+
@configuration_hash = db_config.configuration_hash
|
17
22
|
end
|
18
23
|
|
19
24
|
def create(master_established = false)
|
20
25
|
establish_master_connection unless master_established
|
21
|
-
connection.create_database
|
22
|
-
|
23
|
-
establish_connection configuration
|
24
|
-
rescue ActiveRecord::StatementInvalid => error
|
25
|
-
if error.cause.is_a?(PG::DuplicateDatabase)
|
26
|
-
raise DatabaseAlreadyExists
|
27
|
-
else
|
28
|
-
raise
|
29
|
-
end
|
26
|
+
connection.create_database(db_config.database, configuration_hash.merge(encoding: encoding))
|
27
|
+
establish_connection(db_config)
|
30
28
|
end
|
31
29
|
|
32
30
|
def drop
|
33
31
|
establish_master_connection
|
34
|
-
connection.drop_database
|
32
|
+
connection.drop_database(db_config.database)
|
35
33
|
end
|
36
34
|
|
37
35
|
def charset
|
@@ -54,14 +52,14 @@ module ActiveRecord
|
|
54
52
|
search_path = \
|
55
53
|
case ActiveRecord::Base.dump_schemas
|
56
54
|
when :schema_search_path
|
57
|
-
|
55
|
+
configuration_hash[:schema_search_path]
|
58
56
|
when :all
|
59
57
|
nil
|
60
58
|
when String
|
61
59
|
ActiveRecord::Base.dump_schemas
|
62
60
|
end
|
63
61
|
|
64
|
-
args = ["-
|
62
|
+
args = ["--schema-only", "--no-privileges", "--no-owner", "--file", filename]
|
65
63
|
args.concat(Array(extra_flags)) if extra_flags
|
66
64
|
unless search_path.blank?
|
67
65
|
args += search_path.split(",").map do |part|
|
@@ -74,7 +72,7 @@ module ActiveRecord
|
|
74
72
|
args += ignore_tables.flat_map { |table| ["-T", table] }
|
75
73
|
end
|
76
74
|
|
77
|
-
args <<
|
75
|
+
args << db_config.database
|
78
76
|
run_cmd("pg_dump", args, "dumping")
|
79
77
|
remove_sql_header_comments(filename)
|
80
78
|
File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
|
@@ -82,32 +80,31 @@ module ActiveRecord
|
|
82
80
|
|
83
81
|
def structure_load(filename, extra_flags)
|
84
82
|
set_psql_env
|
85
|
-
args = ["
|
83
|
+
args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--file", filename]
|
86
84
|
args.concat(Array(extra_flags)) if extra_flags
|
87
|
-
args <<
|
85
|
+
args << db_config.database
|
88
86
|
run_cmd("psql", args, "loading")
|
89
87
|
end
|
90
88
|
|
91
89
|
private
|
92
|
-
|
93
|
-
attr_reader :configuration
|
90
|
+
attr_reader :db_config, :configuration_hash
|
94
91
|
|
95
92
|
def encoding
|
96
|
-
|
93
|
+
configuration_hash[:encoding] || DEFAULT_ENCODING
|
97
94
|
end
|
98
95
|
|
99
96
|
def establish_master_connection
|
100
|
-
establish_connection
|
101
|
-
|
102
|
-
|
97
|
+
establish_connection configuration_hash.merge(
|
98
|
+
database: "postgres",
|
99
|
+
schema_search_path: "public"
|
103
100
|
)
|
104
101
|
end
|
105
102
|
|
106
103
|
def set_psql_env
|
107
|
-
ENV["PGHOST"] =
|
108
|
-
ENV["PGPORT"] =
|
109
|
-
ENV["PGPASSWORD"] =
|
110
|
-
ENV["PGUSER"] =
|
104
|
+
ENV["PGHOST"] = db_config.host if db_config.host
|
105
|
+
ENV["PGPORT"] = configuration_hash[:port].to_s if configuration_hash[:port]
|
106
|
+
ENV["PGPASSWORD"] = configuration_hash[:password].to_s if configuration_hash[:password]
|
107
|
+
ENV["PGUSER"] = configuration_hash[:username].to_s if configuration_hash[:username]
|
111
108
|
end
|
112
109
|
|
113
110
|
def run_cmd(cmd, args, action)
|
@@ -5,20 +5,25 @@ module ActiveRecord
|
|
5
5
|
class SQLiteDatabaseTasks # :nodoc:
|
6
6
|
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
7
7
|
|
8
|
-
def
|
9
|
-
|
8
|
+
def self.using_database_configurations?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(db_config, root = ActiveRecord::Tasks::DatabaseTasks.root)
|
13
|
+
@db_config = db_config
|
14
|
+
@root = root
|
10
15
|
end
|
11
16
|
|
12
17
|
def create
|
13
|
-
raise DatabaseAlreadyExists if File.exist?(
|
18
|
+
raise DatabaseAlreadyExists if File.exist?(db_config.database)
|
14
19
|
|
15
|
-
establish_connection
|
20
|
+
establish_connection(db_config)
|
16
21
|
connection
|
17
22
|
end
|
18
23
|
|
19
24
|
def drop
|
20
25
|
require "pathname"
|
21
|
-
path = Pathname.new
|
26
|
+
path = Pathname.new(db_config.database)
|
22
27
|
file = path.absolute? ? path.to_s : File.join(root, path)
|
23
28
|
|
24
29
|
FileUtils.rm(file)
|
@@ -40,7 +45,7 @@ module ActiveRecord
|
|
40
45
|
def structure_dump(filename, extra_flags)
|
41
46
|
args = []
|
42
47
|
args.concat(Array(extra_flags)) if extra_flags
|
43
|
-
args <<
|
48
|
+
args << db_config.database
|
44
49
|
|
45
50
|
ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
|
46
51
|
if ignore_tables.any?
|
@@ -53,14 +58,12 @@ module ActiveRecord
|
|
53
58
|
end
|
54
59
|
|
55
60
|
def structure_load(filename, extra_flags)
|
56
|
-
dbfile = configuration["database"]
|
57
61
|
flags = extra_flags.join(" ") if extra_flags
|
58
|
-
`sqlite3 #{flags} #{
|
62
|
+
`sqlite3 #{flags} #{db_config.database} < "#{filename}"`
|
59
63
|
end
|
60
64
|
|
61
65
|
private
|
62
|
-
|
63
|
-
attr_reader :configuration, :root
|
66
|
+
attr_reader :db_config, :root
|
64
67
|
|
65
68
|
def run_cmd(cmd, args, out)
|
66
69
|
fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
|
@@ -5,18 +5,19 @@ require "active_support/testing/parallelization"
|
|
5
5
|
module ActiveRecord
|
6
6
|
module TestDatabases # :nodoc:
|
7
7
|
ActiveSupport::Testing::Parallelization.after_fork_hook do |i|
|
8
|
-
create_and_load_schema(i, env_name:
|
8
|
+
create_and_load_schema(i, env_name: ActiveRecord::ConnectionHandling::DEFAULT_ENV.call)
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.create_and_load_schema(i, env_name:)
|
12
12
|
old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"
|
13
13
|
|
14
14
|
ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
|
15
|
-
db_config.
|
16
|
-
|
15
|
+
db_config._database = "#{db_config.database}-#{i}"
|
16
|
+
|
17
|
+
ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config, ActiveRecord::Base.schema_format, nil)
|
17
18
|
end
|
18
19
|
ensure
|
19
|
-
ActiveRecord::Base.establish_connection
|
20
|
+
ActiveRecord::Base.establish_connection
|
20
21
|
ENV["VERBOSE"] = old
|
21
22
|
end
|
22
23
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module TestFixtures
|
5
7
|
extend ActiveSupport::Concern
|
@@ -21,7 +23,6 @@ module ActiveRecord
|
|
21
23
|
class_attribute :use_transactional_tests, default: true
|
22
24
|
class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
|
23
25
|
class_attribute :pre_loaded_fixtures, default: false
|
24
|
-
class_attribute :config, default: ActiveRecord::Base
|
25
26
|
class_attribute :lock_threads, default: true
|
26
27
|
end
|
27
28
|
|
@@ -41,8 +42,9 @@ module ActiveRecord
|
|
41
42
|
def fixtures(*fixture_set_names)
|
42
43
|
if fixture_set_names.first == :all
|
43
44
|
raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank?
|
44
|
-
fixture_set_names = Dir["
|
45
|
-
fixture_set_names.
|
45
|
+
fixture_set_names = Dir[::File.join(fixture_path, "{**,*}/*.{yml}")].uniq
|
46
|
+
fixture_set_names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path
|
47
|
+
fixture_set_names.map! { |f| f[fixture_path.to_s.size..-5].delete_prefix("/") }
|
46
48
|
else
|
47
49
|
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
48
50
|
end
|
@@ -97,7 +99,7 @@ module ActiveRecord
|
|
97
99
|
|
98
100
|
def run_in_transaction?
|
99
101
|
use_transactional_tests &&
|
100
|
-
!self.class.uses_transaction?(
|
102
|
+
!self.class.uses_transaction?(name)
|
101
103
|
end
|
102
104
|
|
103
105
|
def setup_fixtures(config = ActiveRecord::Base)
|
@@ -129,10 +131,12 @@ module ActiveRecord
|
|
129
131
|
# When connections are established in the future, begin a transaction too
|
130
132
|
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
131
133
|
spec_name = payload[:spec_name] if payload.key?(:spec_name)
|
134
|
+
shard = payload[:shard] if payload.key?(:shard)
|
135
|
+
setup_shared_connection_pool
|
132
136
|
|
133
137
|
if spec_name
|
134
138
|
begin
|
135
|
-
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
|
139
|
+
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name, shard: shard)
|
136
140
|
rescue ConnectionNotEstablished
|
137
141
|
connection = nil
|
138
142
|
end
|
@@ -179,7 +183,6 @@ module ActiveRecord
|
|
179
183
|
end
|
180
184
|
|
181
185
|
private
|
182
|
-
|
183
186
|
# Shares the writing connection pool with connections on
|
184
187
|
# other handlers.
|
185
188
|
#
|
@@ -187,22 +190,41 @@ module ActiveRecord
|
|
187
190
|
# need to share a connection pool so that the reading connection
|
188
191
|
# can see data in the open transaction on the writing connection.
|
189
192
|
def setup_shared_connection_pool
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
handler
|
195
|
-
|
196
|
-
|
197
|
-
|
193
|
+
if ActiveRecord::Base.legacy_connection_handling
|
194
|
+
writing_handler = ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
|
195
|
+
|
196
|
+
ActiveRecord::Base.connection_handlers.values.each do |handler|
|
197
|
+
if handler != writing_handler
|
198
|
+
handler.connection_pool_names.each do |name|
|
199
|
+
writing_pool_manager = writing_handler.send(:owner_to_pool_manager)[name]
|
200
|
+
return unless writing_pool_manager
|
201
|
+
|
202
|
+
pool_manager = handler.send(:owner_to_pool_manager)[name]
|
203
|
+
pool_manager.shard_names.each do |shard_name|
|
204
|
+
writing_pool_config = writing_pool_manager.get_pool_config(nil, shard_name)
|
205
|
+
pool_manager.set_pool_config(nil, shard_name, writing_pool_config)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
else
|
211
|
+
handler = ActiveRecord::Base.connection_handler
|
212
|
+
|
213
|
+
handler.connection_pool_names.each do |name|
|
214
|
+
pool_manager = handler.send(:owner_to_pool_manager)[name]
|
215
|
+
pool_manager.shard_names.each do |shard_name|
|
216
|
+
writing_pool_config = pool_manager.get_pool_config(ActiveRecord::Base.writing_role, shard_name)
|
217
|
+
pool_manager.role_names.each do |role|
|
218
|
+
next unless pool_manager.get_pool_config(role, shard_name)
|
219
|
+
pool_manager.set_pool_config(role, shard_name, writing_pool_config)
|
220
|
+
end
|
198
221
|
end
|
199
222
|
end
|
200
223
|
end
|
201
224
|
end
|
202
225
|
|
203
226
|
def load_fixtures(config)
|
204
|
-
|
205
|
-
Hash[fixtures.map { |f| [f.name, f] }]
|
227
|
+
ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config).index_by(&:name)
|
206
228
|
end
|
207
229
|
|
208
230
|
def instantiate_fixtures
|
@@ -80,11 +80,11 @@ module ActiveRecord
|
|
80
80
|
|
81
81
|
private
|
82
82
|
def timestamp_attributes_for_create
|
83
|
-
["created_at", "created_on"]
|
83
|
+
["created_at", "created_on"].map! { |name| attribute_aliases[name] || name }
|
84
84
|
end
|
85
85
|
|
86
86
|
def timestamp_attributes_for_update
|
87
|
-
["updated_at", "updated_on"]
|
87
|
+
["updated_at", "updated_on"].map! { |name| attribute_aliases[name] || name }
|
88
88
|
end
|
89
89
|
|
90
90
|
def reload_schema_from_cache
|
@@ -96,15 +96,12 @@ module ActiveRecord
|
|
96
96
|
end
|
97
97
|
|
98
98
|
private
|
99
|
-
|
100
99
|
def _create_record
|
101
100
|
if record_timestamps
|
102
101
|
current_time = current_time_from_proper_timezone
|
103
102
|
|
104
103
|
all_timestamp_attributes_in_model.each do |column|
|
105
|
-
|
106
|
-
_write_attribute(column, current_time)
|
107
|
-
end
|
104
|
+
_write_attribute(column, current_time) unless _read_attribute(column)
|
108
105
|
end
|
109
106
|
end
|
110
107
|
|
@@ -160,7 +157,7 @@ module ActiveRecord
|
|
160
157
|
def clear_timestamp_attributes
|
161
158
|
all_timestamp_attributes_in_model.each do |attribute_name|
|
162
159
|
self[attribute_name] = nil
|
163
|
-
|
160
|
+
clear_attribute_change(attribute_name)
|
164
161
|
end
|
165
162
|
end
|
166
163
|
end
|
@@ -3,22 +3,20 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
# = Active Record Touch Later
|
5
5
|
module TouchLater # :nodoc:
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
before_commit_without_transaction_enrollment :touch_deferred_attributes
|
6
|
+
def before_committed!
|
7
|
+
touch_deferred_attributes if has_defer_touch_attrs? && persisted?
|
8
|
+
super
|
10
9
|
end
|
11
10
|
|
12
11
|
def touch_later(*names) # :nodoc:
|
13
|
-
unless persisted?
|
14
|
-
raise ActiveRecordError, <<-MSG.squish
|
15
|
-
cannot touch on a new or destroyed record object. Consider using
|
16
|
-
persisted?, new_record?, or destroyed? before touching
|
17
|
-
MSG
|
18
|
-
end
|
12
|
+
_raise_record_not_touched_error unless persisted?
|
19
13
|
|
20
14
|
@_defer_touch_attrs ||= timestamp_attributes_for_update_in_model
|
21
|
-
@_defer_touch_attrs |= names
|
15
|
+
@_defer_touch_attrs |= names.map! do |name|
|
16
|
+
name = name.to_s
|
17
|
+
self.class.attribute_aliases[name] || name
|
18
|
+
end unless names.empty?
|
19
|
+
|
22
20
|
@_touch_time = current_time_from_proper_timezone
|
23
21
|
|
24
22
|
surreptitiously_touch @_defer_touch_attrs
|
@@ -36,23 +34,24 @@ module ActiveRecord
|
|
36
34
|
def touch(*names, time: nil) # :nodoc:
|
37
35
|
if has_defer_touch_attrs?
|
38
36
|
names |= @_defer_touch_attrs
|
37
|
+
super(*names, time: time)
|
38
|
+
@_defer_touch_attrs, @_touch_time = nil, nil
|
39
|
+
else
|
40
|
+
super
|
39
41
|
end
|
40
|
-
super(*names, time: time)
|
41
42
|
end
|
42
43
|
|
43
44
|
private
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
def surreptitiously_touch(attr_names)
|
46
|
+
attr_names.each do |attr_name|
|
47
|
+
_write_attribute(attr_name, @_touch_time)
|
48
|
+
clear_attribute_change(attr_name)
|
49
|
+
end
|
48
50
|
end
|
49
51
|
|
50
52
|
def touch_deferred_attributes
|
51
|
-
|
52
|
-
|
53
|
-
touch(*@_defer_touch_attrs, time: @_touch_time)
|
54
|
-
@_defer_touch_attrs, @_touch_time = nil, nil
|
55
|
-
end
|
53
|
+
@_skip_dirty_tracking = true
|
54
|
+
touch(time: @_touch_time)
|
56
55
|
end
|
57
56
|
|
58
57
|
def has_defer_touch_attrs?
|
@@ -10,9 +10,6 @@ module ActiveRecord
|
|
10
10
|
included do
|
11
11
|
define_callbacks :commit, :rollback,
|
12
12
|
:before_commit,
|
13
|
-
:before_commit_without_transaction_enrollment,
|
14
|
-
:commit_without_transaction_enrollment,
|
15
|
-
:rollback_without_transaction_enrollment,
|
16
13
|
scope: [:kind, :name]
|
17
14
|
end
|
18
15
|
|
@@ -164,13 +161,13 @@ module ActiveRecord
|
|
164
161
|
# end
|
165
162
|
# end
|
166
163
|
#
|
167
|
-
# only "Kotori" is created.
|
164
|
+
# only "Kotori" is created.
|
168
165
|
#
|
169
166
|
# Most databases don't support true nested transactions. At the time of
|
170
167
|
# writing, the only database that we're aware of that supports true nested
|
171
168
|
# transactions, is MS-SQL. Because of this, Active Record emulates nested
|
172
|
-
# transactions by using savepoints
|
173
|
-
# https://dev.mysql.com/doc/refman/
|
169
|
+
# transactions by using savepoints. See
|
170
|
+
# https://dev.mysql.com/doc/refman/en/savepoint.html
|
174
171
|
# for more information about savepoints.
|
175
172
|
#
|
176
173
|
# === \Callbacks
|
@@ -208,8 +205,8 @@ module ActiveRecord
|
|
208
205
|
# Note that "TRUNCATE" is also a MySQL DDL statement!
|
209
206
|
module ClassMethods
|
210
207
|
# See the ConnectionAdapters::DatabaseStatements#transaction API docs.
|
211
|
-
def transaction(options
|
212
|
-
connection.transaction(options, &block)
|
208
|
+
def transaction(**options, &block)
|
209
|
+
connection.transaction(**options, &block)
|
213
210
|
end
|
214
211
|
|
215
212
|
def before_commit(*args, &block) # :nodoc:
|
@@ -266,23 +263,7 @@ module ActiveRecord
|
|
266
263
|
set_callback(:rollback, :after, *args, &block)
|
267
264
|
end
|
268
265
|
|
269
|
-
def before_commit_without_transaction_enrollment(*args, &block) # :nodoc:
|
270
|
-
set_options_for_callbacks!(args)
|
271
|
-
set_callback(:before_commit_without_transaction_enrollment, :before, *args, &block)
|
272
|
-
end
|
273
|
-
|
274
|
-
def after_commit_without_transaction_enrollment(*args, &block) # :nodoc:
|
275
|
-
set_options_for_callbacks!(args)
|
276
|
-
set_callback(:commit_without_transaction_enrollment, :after, *args, &block)
|
277
|
-
end
|
278
|
-
|
279
|
-
def after_rollback_without_transaction_enrollment(*args, &block) # :nodoc:
|
280
|
-
set_options_for_callbacks!(args)
|
281
|
-
set_callback(:rollback_without_transaction_enrollment, :after, *args, &block)
|
282
|
-
end
|
283
|
-
|
284
266
|
private
|
285
|
-
|
286
267
|
def set_options_for_callbacks!(args, enforced_options = {})
|
287
268
|
options = args.extract_options!.merge!(enforced_options)
|
288
269
|
args << options
|
@@ -303,28 +284,27 @@ module ActiveRecord
|
|
303
284
|
end
|
304
285
|
|
305
286
|
# See ActiveRecord::Transactions::ClassMethods for detailed documentation.
|
306
|
-
def transaction(options
|
307
|
-
self.class.transaction(options, &block)
|
287
|
+
def transaction(**options, &block)
|
288
|
+
self.class.transaction(**options, &block)
|
308
289
|
end
|
309
290
|
|
310
291
|
def destroy #:nodoc:
|
311
292
|
with_transaction_returning_status { super }
|
312
293
|
end
|
313
294
|
|
314
|
-
def save(
|
295
|
+
def save(**) #:nodoc:
|
315
296
|
with_transaction_returning_status { super }
|
316
297
|
end
|
317
298
|
|
318
|
-
def save!(
|
299
|
+
def save!(**) #:nodoc:
|
319
300
|
with_transaction_returning_status { super }
|
320
301
|
end
|
321
302
|
|
322
|
-
def touch(
|
303
|
+
def touch(*, **) #:nodoc:
|
323
304
|
with_transaction_returning_status { super }
|
324
305
|
end
|
325
306
|
|
326
307
|
def before_committed! # :nodoc:
|
327
|
-
_run_before_commit_without_transaction_enrollment_callbacks
|
328
308
|
_run_before_commit_callbacks
|
329
309
|
end
|
330
310
|
|
@@ -336,11 +316,10 @@ module ActiveRecord
|
|
336
316
|
force_clear_transaction_record_state
|
337
317
|
if should_run_callbacks
|
338
318
|
@_committed_already_called = true
|
339
|
-
_run_commit_without_transaction_enrollment_callbacks
|
340
319
|
_run_commit_callbacks
|
341
320
|
end
|
342
321
|
ensure
|
343
|
-
@_committed_already_called = false
|
322
|
+
@_committed_already_called = @_trigger_update_callback = @_trigger_destroy_callback = false
|
344
323
|
end
|
345
324
|
|
346
325
|
# Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
|
@@ -348,11 +327,11 @@ module ActiveRecord
|
|
348
327
|
def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
|
349
328
|
if should_run_callbacks
|
350
329
|
_run_rollback_callbacks
|
351
|
-
_run_rollback_without_transaction_enrollment_callbacks
|
352
330
|
end
|
353
331
|
ensure
|
354
332
|
restore_transaction_record_state(force_restore_state)
|
355
333
|
clear_transaction_record_state
|
334
|
+
@_trigger_update_callback = @_trigger_destroy_callback = false if force_restore_state
|
356
335
|
end
|
357
336
|
|
358
337
|
# Executes +method+ within a transaction and captures its return value as a
|
@@ -363,13 +342,11 @@ module ActiveRecord
|
|
363
342
|
# instance.
|
364
343
|
def with_transaction_returning_status
|
365
344
|
status = nil
|
366
|
-
self.class.
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
@transaction_state = self.class.connection.transaction_state
|
372
|
-
end
|
345
|
+
connection = self.class.connection
|
346
|
+
ensure_finalize = !connection.transaction_open?
|
347
|
+
|
348
|
+
connection.transaction do
|
349
|
+
add_to_transaction(ensure_finalize || has_transactional_callbacks?)
|
373
350
|
remember_transaction_record_state
|
374
351
|
|
375
352
|
status = yield
|
@@ -391,6 +368,7 @@ module ActiveRecord
|
|
391
368
|
@_start_transaction_state ||= {
|
392
369
|
id: id,
|
393
370
|
new_record: @new_record,
|
371
|
+
previously_new_record: @previously_new_record,
|
394
372
|
destroyed: @destroyed,
|
395
373
|
attributes: @attributes,
|
396
374
|
frozen?: frozen?,
|
@@ -415,7 +393,6 @@ module ActiveRecord
|
|
415
393
|
# Force to clear the transaction record state.
|
416
394
|
def force_clear_transaction_record_state
|
417
395
|
@_start_transaction_state = nil
|
418
|
-
@transaction_state = nil
|
419
396
|
end
|
420
397
|
|
421
398
|
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
|
@@ -423,6 +400,7 @@ module ActiveRecord
|
|
423
400
|
if restore_state = @_start_transaction_state
|
424
401
|
if force_restore_state || restore_state[:level] <= 1
|
425
402
|
@new_record = restore_state[:new_record]
|
403
|
+
@previously_new_record = restore_state[:previously_new_record]
|
426
404
|
@destroyed = restore_state[:destroyed]
|
427
405
|
@attributes = restore_state[:attributes].map do |attr|
|
428
406
|
value = @attributes.fetch_value(attr.name)
|
@@ -455,39 +433,12 @@ module ActiveRecord
|
|
455
433
|
|
456
434
|
# Add the record to the current transaction so that the #after_rollback and #after_commit
|
457
435
|
# callbacks can be called.
|
458
|
-
def add_to_transaction
|
459
|
-
self.class.connection.add_transaction_record(self)
|
436
|
+
def add_to_transaction(ensure_finalize = true)
|
437
|
+
self.class.connection.add_transaction_record(self, ensure_finalize)
|
460
438
|
end
|
461
439
|
|
462
440
|
def has_transactional_callbacks?
|
463
441
|
!_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
|
464
442
|
end
|
465
|
-
|
466
|
-
# Updates the attributes on this particular Active Record object so that
|
467
|
-
# if it's associated with a transaction, then the state of the Active Record
|
468
|
-
# object will be updated to reflect the current state of the transaction.
|
469
|
-
#
|
470
|
-
# The <tt>@transaction_state</tt> variable stores the states of the associated
|
471
|
-
# transaction. This relies on the fact that a transaction can only be in
|
472
|
-
# one rollback or commit (otherwise a list of states would be required).
|
473
|
-
# Each Active Record object inside of a transaction carries that transaction's
|
474
|
-
# TransactionState.
|
475
|
-
#
|
476
|
-
# This method checks to see if the ActiveRecord object's state reflects
|
477
|
-
# the TransactionState, and rolls back or commits the Active Record object
|
478
|
-
# as appropriate.
|
479
|
-
def sync_with_transaction_state
|
480
|
-
if transaction_state = @transaction_state
|
481
|
-
if transaction_state.fully_committed?
|
482
|
-
force_clear_transaction_record_state
|
483
|
-
elsif transaction_state.committed?
|
484
|
-
clear_transaction_record_state
|
485
|
-
elsif transaction_state.rolledback?
|
486
|
-
force_restore_state = transaction_state.fully_rolledback?
|
487
|
-
restore_transaction_record_state(force_restore_state)
|
488
|
-
clear_transaction_record_state
|
489
|
-
end
|
490
|
-
end
|
491
|
-
end
|
492
443
|
end
|
493
444
|
end
|
@@ -11,14 +11,13 @@ module ActiveRecord
|
|
11
11
|
end
|
12
12
|
|
13
13
|
private
|
14
|
-
|
15
14
|
def registration_klass
|
16
15
|
Registration
|
17
16
|
end
|
18
17
|
|
19
|
-
def find_registration(symbol, *args)
|
18
|
+
def find_registration(symbol, *args, **kwargs)
|
20
19
|
registrations
|
21
|
-
.select { |registration| registration.matches?(symbol, *args) }
|
20
|
+
.select { |registration| registration.matches?(symbol, *args, **kwargs) }
|
22
21
|
.max
|
23
22
|
end
|
24
23
|
end
|
@@ -53,7 +52,6 @@ module ActiveRecord
|
|
53
52
|
end
|
54
53
|
|
55
54
|
protected
|
56
|
-
|
57
55
|
attr_reader :name, :block, :adapter, :override
|
58
56
|
|
59
57
|
def priority
|
@@ -72,7 +70,6 @@ module ActiveRecord
|
|
72
70
|
end
|
73
71
|
|
74
72
|
private
|
75
|
-
|
76
73
|
def matches_adapter?(adapter: nil, **)
|
77
74
|
(self.adapter.nil? || adapter == self.adapter)
|
78
75
|
end
|
@@ -56,15 +56,18 @@ module ActiveRecord
|
|
56
56
|
end
|
57
57
|
|
58
58
|
private
|
59
|
-
|
60
59
|
def default_value?(value)
|
61
60
|
value == coder.load(nil)
|
62
61
|
end
|
63
62
|
|
64
63
|
def encoded(value)
|
65
|
-
|
66
|
-
|
64
|
+
return if default_value?(value)
|
65
|
+
payload = coder.dump(value)
|
66
|
+
if payload && binary? && payload.encoding != Encoding::BINARY
|
67
|
+
payload = payload.dup if payload.frozen?
|
68
|
+
payload.force_encoding(Encoding::BINARY)
|
67
69
|
end
|
70
|
+
payload
|
68
71
|
end
|
69
72
|
end
|
70
73
|
end
|