activerecord 6.0.0.beta3 → 6.0.2.rc2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +466 -9
- data/README.rdoc +3 -1
- data/lib/active_record.rb +0 -1
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +4 -3
- data/lib/active_record/associations/association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +5 -2
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +6 -2
- data/lib/active_record/associations/collection_proxy.rb +2 -2
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/join_dependency.rb +14 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +12 -3
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/preloader/association.rb +34 -30
- data/lib/active_record/associations/preloader/through_association.rb +48 -28
- data/lib/active_record/attribute_methods.rb +3 -53
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +47 -14
- data/lib/active_record/attribute_methods/primary_key.rb +7 -15
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +3 -9
- data/lib/active_record/attribute_methods/write.rb +6 -12
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +21 -7
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -11
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +88 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +79 -22
- data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -4
- data/lib/active_record/connection_adapters/abstract_adapter.rb +111 -33
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +78 -73
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +48 -8
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -5
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +9 -6
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +39 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +34 -38
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +67 -26
- data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -114
- data/lib/active_record/connection_handling.rb +31 -13
- data/lib/active_record/core.rb +23 -24
- data/lib/active_record/database_configurations.rb +73 -44
- data/lib/active_record/database_configurations/hash_config.rb +11 -11
- data/lib/active_record/database_configurations/url_config.rb +12 -12
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +15 -0
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/fixtures.rb +11 -6
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +13 -1
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +3 -4
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/middleware/database_selector.rb +3 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -6
- data/lib/active_record/migration.rb +62 -44
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +10 -0
- data/lib/active_record/model_schema.rb +3 -0
- data/lib/active_record/persistence.rb +206 -13
- data/lib/active_record/querying.rb +17 -12
- data/lib/active_record/railtie.rb +0 -1
- data/lib/active_record/railties/databases.rake +127 -25
- data/lib/active_record/reflection.rb +3 -3
- data/lib/active_record/relation.rb +99 -20
- data/lib/active_record/relation/calculations.rb +38 -40
- data/lib/active_record/relation/delegation.rb +22 -30
- data/lib/active_record/relation/finder_methods.rb +17 -12
- data/lib/active_record/relation/merger.rb +11 -16
- data/lib/active_record/relation/query_methods.rb +228 -76
- data/lib/active_record/relation/where_clause.rb +9 -5
- data/lib/active_record/sanitization.rb +33 -4
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +10 -1
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/store.rb +48 -0
- data/lib/active_record/table_metadata.rb +9 -13
- data/lib/active_record/tasks/database_tasks.rb +109 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
- data/lib/active_record/test_databases.rb +1 -16
- data/lib/active_record/test_fixtures.rb +1 -0
- data/lib/active_record/timestamp.rb +26 -16
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +56 -46
- data/lib/active_record/type_caster/connection.rb +16 -10
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +3 -5
- data/lib/arel.rb +12 -5
- data/lib/arel/insert_manager.rb +3 -3
- data/lib/arel/nodes.rb +2 -1
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/select_core.rb +16 -12
- data/lib/arel/nodes/unary.rb +1 -0
- data/lib/arel/nodes/values_list.rb +2 -17
- data/lib/arel/select_manager.rb +10 -10
- data/lib/arel/visitors/depth_first.rb +7 -2
- data/lib/arel/visitors/dot.rb +7 -2
- data/lib/arel/visitors/ibm_db.rb +13 -0
- data/lib/arel/visitors/informix.rb +6 -0
- data/lib/arel/visitors/mssql.rb +15 -1
- data/lib/arel/visitors/oracle12.rb +4 -5
- data/lib/arel/visitors/postgresql.rb +4 -10
- data/lib/arel/visitors/to_sql.rb +107 -131
- data/lib/arel/visitors/visitor.rb +9 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +16 -12
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -3,6 +3,8 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Tasks # :nodoc:
|
5
5
|
class MySQLDatabaseTasks # :nodoc:
|
6
|
+
ER_DB_CREATE_EXISTS = 1007
|
7
|
+
|
6
8
|
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
7
9
|
|
8
10
|
def initialize(configuration)
|
@@ -14,7 +16,7 @@ module ActiveRecord
|
|
14
16
|
connection.create_database configuration["database"], creation_options
|
15
17
|
establish_connection configuration
|
16
18
|
rescue ActiveRecord::StatementInvalid => error
|
17
|
-
if error.
|
19
|
+
if connection.error_number(error.cause) == ER_DB_CREATE_EXISTS
|
18
20
|
raise DatabaseAlreadyExists
|
19
21
|
else
|
20
22
|
raise
|
@@ -8,31 +8,16 @@ module ActiveRecord
|
|
8
8
|
create_and_load_schema(i, env_name: Rails.env)
|
9
9
|
end
|
10
10
|
|
11
|
-
ActiveSupport::Testing::Parallelization.run_cleanup_hook do
|
12
|
-
drop(env_name: Rails.env)
|
13
|
-
end
|
14
|
-
|
15
11
|
def self.create_and_load_schema(i, env_name:)
|
16
12
|
old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"
|
17
13
|
|
18
14
|
ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
|
19
15
|
db_config.config["database"] += "-#{i}"
|
20
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
21
|
-
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config.config, ActiveRecord::Base.schema_format, nil, env_name, db_config.spec_name)
|
16
|
+
ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config.config, ActiveRecord::Base.schema_format, nil, env_name, db_config.spec_name)
|
22
17
|
end
|
23
18
|
ensure
|
24
19
|
ActiveRecord::Base.establish_connection(Rails.env.to_sym)
|
25
20
|
ENV["VERBOSE"] = old
|
26
21
|
end
|
27
|
-
|
28
|
-
def self.drop(env_name:)
|
29
|
-
old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"
|
30
|
-
|
31
|
-
ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
|
32
|
-
ActiveRecord::Tasks::DatabaseTasks.drop(db_config.config)
|
33
|
-
end
|
34
|
-
ensure
|
35
|
-
ENV["VERBOSE"] = old
|
36
|
-
end
|
37
22
|
end
|
38
23
|
end
|
@@ -129,6 +129,7 @@ module ActiveRecord
|
|
129
129
|
# When connections are established in the future, begin a transaction too
|
130
130
|
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
131
131
|
spec_name = payload[:spec_name] if payload.key?(:spec_name)
|
132
|
+
setup_shared_connection_pool
|
132
133
|
|
133
134
|
if spec_name
|
134
135
|
begin
|
@@ -59,19 +59,26 @@ module ActiveRecord
|
|
59
59
|
attribute_names.index_with(time || current_time_from_proper_timezone)
|
60
60
|
end
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
timestamp_attributes_for_create
|
65
|
-
|
62
|
+
def timestamp_attributes_for_create_in_model
|
63
|
+
@timestamp_attributes_for_create_in_model ||=
|
64
|
+
(timestamp_attributes_for_create & column_names).freeze
|
65
|
+
end
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
def timestamp_attributes_for_update_in_model
|
68
|
+
@timestamp_attributes_for_update_in_model ||=
|
69
|
+
(timestamp_attributes_for_update & column_names).freeze
|
70
|
+
end
|
70
71
|
|
71
|
-
|
72
|
-
|
73
|
-
|
72
|
+
def all_timestamp_attributes_in_model
|
73
|
+
@all_timestamp_attributes_in_model ||=
|
74
|
+
(timestamp_attributes_for_create_in_model + timestamp_attributes_for_update_in_model).freeze
|
75
|
+
end
|
74
76
|
|
77
|
+
def current_time_from_proper_timezone
|
78
|
+
default_timezone == :utc ? Time.now.utc : Time.now
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
75
82
|
def timestamp_attributes_for_create
|
76
83
|
["created_at", "created_on"]
|
77
84
|
end
|
@@ -80,8 +87,11 @@ module ActiveRecord
|
|
80
87
|
["updated_at", "updated_on"]
|
81
88
|
end
|
82
89
|
|
83
|
-
def
|
84
|
-
|
90
|
+
def reload_schema_from_cache
|
91
|
+
@timestamp_attributes_for_create_in_model = nil
|
92
|
+
@timestamp_attributes_for_update_in_model = nil
|
93
|
+
@all_timestamp_attributes_in_model = nil
|
94
|
+
super
|
85
95
|
end
|
86
96
|
end
|
87
97
|
|
@@ -124,19 +134,19 @@ module ActiveRecord
|
|
124
134
|
end
|
125
135
|
|
126
136
|
def timestamp_attributes_for_create_in_model
|
127
|
-
self.class.
|
137
|
+
self.class.timestamp_attributes_for_create_in_model
|
128
138
|
end
|
129
139
|
|
130
140
|
def timestamp_attributes_for_update_in_model
|
131
|
-
self.class.
|
141
|
+
self.class.timestamp_attributes_for_update_in_model
|
132
142
|
end
|
133
143
|
|
134
144
|
def all_timestamp_attributes_in_model
|
135
|
-
self.class.
|
145
|
+
self.class.all_timestamp_attributes_in_model
|
136
146
|
end
|
137
147
|
|
138
148
|
def current_time_from_proper_timezone
|
139
|
-
self.class.
|
149
|
+
self.class.current_time_from_proper_timezone
|
140
150
|
end
|
141
151
|
|
142
152
|
def max_updated_column_timestamp
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
# = Active Record Touch Later
|
5
|
-
module TouchLater
|
5
|
+
module TouchLater # :nodoc:
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
@@ -22,7 +22,8 @@ module ActiveRecord
|
|
22
22
|
@_touch_time = current_time_from_proper_timezone
|
23
23
|
|
24
24
|
surreptitiously_touch @_defer_touch_attrs
|
25
|
-
|
25
|
+
add_to_transaction
|
26
|
+
@_new_record_before_last_commit ||= false
|
26
27
|
|
27
28
|
# touch the parents as we are not calling the after_save callbacks
|
28
29
|
self.class.reflect_on_all_associations(:belongs_to).each do |r|
|
@@ -48,6 +49,7 @@ module ActiveRecord
|
|
48
49
|
|
49
50
|
def touch_deferred_attributes
|
50
51
|
if has_defer_touch_attrs? && persisted?
|
52
|
+
@_skip_dirty_tracking = true
|
51
53
|
touch(*@_defer_touch_attrs, time: @_touch_time)
|
52
54
|
@_defer_touch_attrs, @_touch_time = nil, nil
|
53
55
|
end
|
@@ -234,6 +234,12 @@ module ActiveRecord
|
|
234
234
|
set_callback(:commit, :after, *args, &block)
|
235
235
|
end
|
236
236
|
|
237
|
+
# Shortcut for <tt>after_commit :hook, on: [ :create, :update ]</tt>.
|
238
|
+
def after_save_commit(*args, &block)
|
239
|
+
set_options_for_callbacks!(args, on: [ :create, :update ])
|
240
|
+
set_callback(:commit, :after, *args, &block)
|
241
|
+
end
|
242
|
+
|
237
243
|
# Shortcut for <tt>after_commit :hook, on: :create</tt>.
|
238
244
|
def after_create_commit(*args, &block)
|
239
245
|
set_options_for_callbacks!(args, on: :create)
|
@@ -327,14 +333,14 @@ module ActiveRecord
|
|
327
333
|
# Ensure that it is not called if the object was never persisted (failed create),
|
328
334
|
# but call it after the commit of a destroyed object.
|
329
335
|
def committed!(should_run_callbacks: true) #:nodoc:
|
330
|
-
|
336
|
+
force_clear_transaction_record_state
|
337
|
+
if should_run_callbacks
|
331
338
|
@_committed_already_called = true
|
332
339
|
_run_commit_without_transaction_enrollment_callbacks
|
333
340
|
_run_commit_callbacks
|
334
341
|
end
|
335
342
|
ensure
|
336
343
|
@_committed_already_called = false
|
337
|
-
force_clear_transaction_record_state
|
338
344
|
end
|
339
345
|
|
340
346
|
# Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
|
@@ -349,18 +355,6 @@ module ActiveRecord
|
|
349
355
|
clear_transaction_record_state
|
350
356
|
end
|
351
357
|
|
352
|
-
# Add the record to the current transaction so that the #after_rollback and #after_commit callbacks
|
353
|
-
# can be called.
|
354
|
-
def add_to_transaction
|
355
|
-
if has_transactional_callbacks?
|
356
|
-
self.class.connection.add_transaction_record(self)
|
357
|
-
else
|
358
|
-
sync_with_transaction_state
|
359
|
-
set_transaction_state(self.class.connection.transaction_state)
|
360
|
-
end
|
361
|
-
remember_transaction_record_state
|
362
|
-
end
|
363
|
-
|
364
358
|
# Executes +method+ within a transaction and captures its return value as a
|
365
359
|
# status flag. If the status is true the transaction is committed, otherwise
|
366
360
|
# a ROLLBACK is issued. In any case the status flag is returned.
|
@@ -370,29 +364,40 @@ module ActiveRecord
|
|
370
364
|
def with_transaction_returning_status
|
371
365
|
status = nil
|
372
366
|
self.class.transaction do
|
373
|
-
|
367
|
+
if has_transactional_callbacks?
|
368
|
+
add_to_transaction
|
369
|
+
else
|
370
|
+
sync_with_transaction_state if @transaction_state&.finalized?
|
371
|
+
@transaction_state = self.class.connection.transaction_state
|
372
|
+
end
|
373
|
+
remember_transaction_record_state
|
374
|
+
|
374
375
|
status = yield
|
375
376
|
raise ActiveRecord::Rollback unless status
|
376
377
|
end
|
377
378
|
status
|
378
379
|
end
|
379
380
|
|
381
|
+
def trigger_transactional_callbacks? # :nodoc:
|
382
|
+
(@_new_record_before_last_commit || _trigger_update_callback) && persisted? ||
|
383
|
+
_trigger_destroy_callback && destroyed?
|
384
|
+
end
|
385
|
+
|
380
386
|
private
|
381
387
|
attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
|
382
388
|
|
383
389
|
# Save the new record state and id of a record so it can be restored later if a transaction fails.
|
384
390
|
def remember_transaction_record_state
|
385
|
-
@_start_transaction_state
|
391
|
+
@_start_transaction_state ||= {
|
386
392
|
id: id,
|
387
393
|
new_record: @new_record,
|
388
394
|
destroyed: @destroyed,
|
395
|
+
attributes: @attributes,
|
389
396
|
frozen?: frozen?,
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
end
|
397
|
+
level: 0
|
398
|
+
}
|
399
|
+
@_start_transaction_state[:level] += 1
|
394
400
|
|
395
|
-
def remember_new_record_before_last_commit
|
396
401
|
if _committed_already_called
|
397
402
|
@_new_record_before_last_commit = false
|
398
403
|
else
|
@@ -402,27 +407,32 @@ module ActiveRecord
|
|
402
407
|
|
403
408
|
# Clear the new record state and id of a record.
|
404
409
|
def clear_transaction_record_state
|
405
|
-
|
410
|
+
return unless @_start_transaction_state
|
411
|
+
@_start_transaction_state[:level] -= 1
|
406
412
|
force_clear_transaction_record_state if @_start_transaction_state[:level] < 1
|
407
413
|
end
|
408
414
|
|
409
415
|
# Force to clear the transaction record state.
|
410
416
|
def force_clear_transaction_record_state
|
411
|
-
@_start_transaction_state
|
417
|
+
@_start_transaction_state = nil
|
418
|
+
@transaction_state = nil
|
412
419
|
end
|
413
420
|
|
414
421
|
# Restore the new record state and id of a record that was previously saved by a call to save_record_state.
|
415
|
-
def restore_transaction_record_state(
|
416
|
-
|
417
|
-
|
418
|
-
if transaction_level < 1 || force
|
419
|
-
restore_state = @_start_transaction_state
|
420
|
-
thaw
|
422
|
+
def restore_transaction_record_state(force_restore_state = false)
|
423
|
+
if restore_state = @_start_transaction_state
|
424
|
+
if force_restore_state || restore_state[:level] <= 1
|
421
425
|
@new_record = restore_state[:new_record]
|
422
426
|
@destroyed = restore_state[:destroyed]
|
423
|
-
|
424
|
-
|
425
|
-
|
427
|
+
@attributes = restore_state[:attributes].map do |attr|
|
428
|
+
value = @attributes.fetch_value(attr.name)
|
429
|
+
attr = attr.with_value_from_user(value) if attr.value != value
|
430
|
+
attr
|
431
|
+
end
|
432
|
+
@mutations_from_database = nil
|
433
|
+
@mutations_before_last_save = nil
|
434
|
+
if @attributes.fetch_value(@primary_key) != restore_state[:id]
|
435
|
+
@attributes.write_from_user(@primary_key, restore_state[:id])
|
426
436
|
end
|
427
437
|
freeze if restore_state[:frozen?]
|
428
438
|
end
|
@@ -443,8 +453,10 @@ module ActiveRecord
|
|
443
453
|
end
|
444
454
|
end
|
445
455
|
|
446
|
-
|
447
|
-
|
456
|
+
# Add the record to the current transaction so that the #after_rollback and #after_commit
|
457
|
+
# callbacks can be called.
|
458
|
+
def add_to_transaction
|
459
|
+
self.class.connection.add_transaction_record(self)
|
448
460
|
end
|
449
461
|
|
450
462
|
def has_transactional_callbacks?
|
@@ -464,19 +476,17 @@ module ActiveRecord
|
|
464
476
|
# This method checks to see if the ActiveRecord object's state reflects
|
465
477
|
# the TransactionState, and rolls back or commits the Active Record object
|
466
478
|
# as appropriate.
|
467
|
-
#
|
468
|
-
# Since Active Record objects can be inside multiple transactions, this
|
469
|
-
# method recursively goes through the parent of the TransactionState and
|
470
|
-
# checks if the Active Record object reflects the state of the object.
|
471
479
|
def sync_with_transaction_state
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
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
|
480
490
|
end
|
481
491
|
end
|
482
492
|
end
|
@@ -8,21 +8,27 @@ module ActiveRecord
|
|
8
8
|
@table_name = table_name
|
9
9
|
end
|
10
10
|
|
11
|
-
def type_cast_for_database(
|
11
|
+
def type_cast_for_database(attr_name, value)
|
12
12
|
return value if value.is_a?(Arel::Nodes::BindParam)
|
13
|
-
|
14
|
-
|
13
|
+
type = type_for_attribute(attr_name)
|
14
|
+
type.serialize(value)
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
delegate :connection, to: :@klass
|
17
|
+
def type_for_attribute(attr_name)
|
18
|
+
schema_cache = connection.schema_cache
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
20
|
+
if schema_cache.data_source_exists?(table_name)
|
21
|
+
column = schema_cache.columns_hash(table_name)[attr_name.to_s]
|
22
|
+
type = connection.lookup_cast_type_from_column(column) if column
|
25
23
|
end
|
24
|
+
|
25
|
+
type || Type.default_value
|
26
|
+
end
|
27
|
+
|
28
|
+
delegate :connection, to: :@klass, private: true
|
29
|
+
|
30
|
+
private
|
31
|
+
attr_reader :table_name
|
26
32
|
end
|
27
33
|
end
|
28
34
|
end
|
@@ -40,6 +40,7 @@ module ActiveRecord
|
|
40
40
|
include ActiveModel::Validations
|
41
41
|
|
42
42
|
# The validation process on save can be skipped by passing <tt>validate: false</tt>.
|
43
|
+
# The validation context can be changed by passing <tt>context: context</tt>.
|
43
44
|
# The regular {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] method is replaced
|
44
45
|
# with this when the validations module is mixed in, which it is by default.
|
45
46
|
def save(options = {})
|
@@ -25,7 +25,7 @@ module ActiveRecord
|
|
25
25
|
if finder_class.primary_key
|
26
26
|
relation = relation.where.not(finder_class.primary_key => record.id_in_database)
|
27
27
|
else
|
28
|
-
raise UnknownPrimaryKey.new(finder_class, "
|
28
|
+
raise UnknownPrimaryKey.new(finder_class, "Cannot validate uniqueness for persisted record without primary key.")
|
29
29
|
end
|
30
30
|
end
|
31
31
|
relation = scope_relation(record, relation)
|
@@ -60,10 +60,8 @@ module ActiveRecord
|
|
60
60
|
comparison = relation.bind_attribute(attribute, value) do |attr, bind|
|
61
61
|
return relation.none! if bind.unboundable?
|
62
62
|
|
63
|
-
if bind.nil?
|
64
|
-
|
65
|
-
elsif !options.key?(:case_sensitive)
|
66
|
-
klass.connection.default_uniqueness_comparison(attr, bind)
|
63
|
+
if !options.key?(:case_sensitive) || bind.nil?
|
64
|
+
klass.connection.default_uniqueness_comparison(attr, bind, klass)
|
67
65
|
elsif options[:case_sensitive]
|
68
66
|
klass.connection.case_sensitive_comparison(attr, bind)
|
69
67
|
else
|
data/lib/arel.rb
CHANGED
@@ -24,22 +24,29 @@ require "arel/update_manager"
|
|
24
24
|
require "arel/delete_manager"
|
25
25
|
require "arel/nodes"
|
26
26
|
|
27
|
-
module Arel
|
27
|
+
module Arel
|
28
28
|
VERSION = "10.0.0"
|
29
29
|
|
30
|
+
# Wrap a known-safe SQL string for passing to query methods, e.g.
|
31
|
+
#
|
32
|
+
# Post.order(Arel.sql("length(title)")).last
|
33
|
+
#
|
34
|
+
# Great caution should be taken to avoid SQL injection vulnerabilities.
|
35
|
+
# This method should not be used with unsafe values such as request
|
36
|
+
# parameters or model attributes.
|
30
37
|
def self.sql(raw_sql)
|
31
38
|
Arel::Nodes::SqlLiteral.new raw_sql
|
32
39
|
end
|
33
40
|
|
34
|
-
def self.star
|
41
|
+
def self.star # :nodoc:
|
35
42
|
sql "*"
|
36
43
|
end
|
37
44
|
|
38
|
-
def self.arel_node?(value)
|
45
|
+
def self.arel_node?(value) # :nodoc:
|
39
46
|
value.is_a?(Arel::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
|
40
47
|
end
|
41
48
|
|
42
|
-
def self.fetch_attribute(value)
|
49
|
+
def self.fetch_attribute(value) # :nodoc:
|
43
50
|
case value
|
44
51
|
when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
|
45
52
|
yield value.left.is_a?(Arel::Attributes::Attribute) ? value.left : value.right
|
@@ -47,5 +54,5 @@ module Arel # :nodoc: all
|
|
47
54
|
end
|
48
55
|
|
49
56
|
## Convenience Alias
|
50
|
-
Node = Arel::Nodes::Node
|
57
|
+
Node = Arel::Nodes::Node # :nodoc:
|
51
58
|
end
|