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,13 +1,11 @@
|
|
1
|
-
require 'active_support/core_ext/array/wrap'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
|
-
# = Active Record Callbacks
|
2
|
+
# = Active Record \Callbacks
|
5
3
|
#
|
6
|
-
# Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
|
4
|
+
# \Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
|
7
5
|
# before or after an alteration of the object state. This can be used to make sure that associated and
|
8
|
-
# dependent objects are deleted when
|
9
|
-
# before they're validated (by overwriting +before_validation+).
|
10
|
-
# the
|
6
|
+
# dependent objects are deleted when {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] is called (by overwriting +before_destroy+) or
|
7
|
+
# to massage attributes before they're validated (by overwriting +before_validation+).
|
8
|
+
# As an example of the callbacks initiated, consider the {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] call for a new record:
|
11
9
|
#
|
12
10
|
# * (-) <tt>save</tt>
|
13
11
|
# * (-) <tt>valid</tt>
|
@@ -22,22 +20,25 @@ module ActiveRecord
|
|
22
20
|
# * (7) <tt>after_commit</tt>
|
23
21
|
#
|
24
22
|
# Also, an <tt>after_rollback</tt> callback can be configured to be triggered whenever a rollback is issued.
|
25
|
-
# Check out
|
23
|
+
# Check out ActiveRecord::Transactions for more details about <tt>after_commit</tt> and
|
26
24
|
# <tt>after_rollback</tt>.
|
27
25
|
#
|
28
|
-
#
|
26
|
+
# Additionally, an <tt>after_touch</tt> callback is triggered whenever an
|
27
|
+
# object is touched.
|
28
|
+
#
|
29
|
+
# Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
|
29
30
|
# is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
|
30
31
|
# are instantiated as well.
|
31
32
|
#
|
32
|
-
#
|
33
|
-
# Active Record life cycle. The sequence for calling
|
33
|
+
# There are nineteen callbacks in total, which give you immense power to react and prepare for each state in the
|
34
|
+
# Active Record life cycle. The sequence for calling {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] for an existing record is similar,
|
34
35
|
# except that each <tt>_create</tt> callback is replaced by the corresponding <tt>_update</tt> callback.
|
35
36
|
#
|
36
37
|
# Examples:
|
37
38
|
# class CreditCard < ActiveRecord::Base
|
38
39
|
# # Strip everything but digits, so the user can specify "555 234 34" or
|
39
|
-
# # "5552-3434"
|
40
|
-
# before_validation(:
|
40
|
+
# # "5552-3434" and both will mean "55523434"
|
41
|
+
# before_validation(on: :create) do
|
41
42
|
# self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
|
42
43
|
# end
|
43
44
|
# end
|
@@ -52,9 +53,9 @@ module ActiveRecord
|
|
52
53
|
# end
|
53
54
|
#
|
54
55
|
# class Firm < ActiveRecord::Base
|
55
|
-
# #
|
56
|
-
# before_destroy { |record| Person.
|
57
|
-
# before_destroy { |record| Client.
|
56
|
+
# # Disables access to the system, for associated clients and people when the firm is destroyed
|
57
|
+
# before_destroy { |record| Person.where(firm_id: record.id).update_all(access: 'disabled') }
|
58
|
+
# before_destroy { |record| Client.where(client_of: record.id).update_all(access: 'disabled') }
|
58
59
|
# end
|
59
60
|
#
|
60
61
|
# == Inheritable callback queues
|
@@ -85,7 +86,7 @@ module ActiveRecord
|
|
85
86
|
#
|
86
87
|
# In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+.
|
87
88
|
# So, use the callback macros when you want to ensure that a certain callback is called for the entire
|
88
|
-
# hierarchy, and use the regular
|
89
|
+
# hierarchy, and use the regular overwritable methods when you want to leave it up to each descendant
|
89
90
|
# to decide whether they want to call +super+ and trigger the inherited callbacks.
|
90
91
|
#
|
91
92
|
# *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
|
@@ -127,7 +128,7 @@ module ActiveRecord
|
|
127
128
|
# record.credit_card_number = decrypt(record.credit_card_number)
|
128
129
|
# end
|
129
130
|
#
|
130
|
-
# alias_method :
|
131
|
+
# alias_method :after_initialize, :after_save
|
131
132
|
#
|
132
133
|
# private
|
133
134
|
# def encrypt(value)
|
@@ -162,7 +163,7 @@ module ActiveRecord
|
|
162
163
|
# record.send("#{@attribute}=", decrypt(record.send("#{@attribute}")))
|
163
164
|
# end
|
164
165
|
#
|
165
|
-
# alias_method :
|
166
|
+
# alias_method :after_initialize, :after_save
|
166
167
|
#
|
167
168
|
# private
|
168
169
|
# def encrypt(value)
|
@@ -174,64 +175,86 @@ module ActiveRecord
|
|
174
175
|
# end
|
175
176
|
# end
|
176
177
|
#
|
177
|
-
#
|
178
|
-
# pass a "method string", which will then be evaluated within the binding of the callback. Example:
|
178
|
+
# == <tt>before_validation*</tt> returning statements
|
179
179
|
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
#
|
180
|
+
# If the +before_validation+ callback throws +:abort+, the process will be
|
181
|
+
# aborted and {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] will return +false+.
|
182
|
+
# If {ActiveRecord::Base#save!}[rdoc-ref:Persistence#save!] is called it will raise an ActiveRecord::RecordInvalid exception.
|
183
|
+
# Nothing will be appended to the errors object.
|
184
|
+
#
|
185
|
+
# == Canceling callbacks
|
186
|
+
#
|
187
|
+
# If a <tt>before_*</tt> callback throws +:abort+, all the later callbacks and
|
188
|
+
# the associated action are cancelled.
|
189
|
+
# Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
|
190
|
+
# methods on the model, which are called last.
|
191
|
+
#
|
192
|
+
# == Ordering callbacks
|
193
|
+
#
|
194
|
+
# Sometimes the code needs that the callbacks execute in a specific order. For example, a +before_destroy+
|
195
|
+
# callback (+log_children+ in this case) should be executed before the children get destroyed by the
|
196
|
+
# <tt>dependent: :destroy</tt> option.
|
183
197
|
#
|
184
|
-
#
|
185
|
-
# is triggered. Also note that these inline callbacks can be stacked just like the regular ones:
|
198
|
+
# Let's look at the code below:
|
186
199
|
#
|
187
200
|
# class Topic < ActiveRecord::Base
|
188
|
-
#
|
189
|
-
#
|
201
|
+
# has_many :children, dependent: :destroy
|
202
|
+
#
|
203
|
+
# before_destroy :log_children
|
204
|
+
#
|
205
|
+
# private
|
206
|
+
# def log_children
|
207
|
+
# # Child processing
|
208
|
+
# end
|
190
209
|
# end
|
191
210
|
#
|
192
|
-
#
|
211
|
+
# In this case, the problem is that when the +before_destroy+ callback is executed, the children are not available
|
212
|
+
# because the {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] callback gets executed first.
|
213
|
+
# You can use the +prepend+ option on the +before_destroy+ callback to avoid this.
|
193
214
|
#
|
194
|
-
#
|
195
|
-
#
|
196
|
-
# ActiveRecord::RecordInvalid exception. Nothing will be appended to the errors object.
|
215
|
+
# class Topic < ActiveRecord::Base
|
216
|
+
# has_many :children, dependent: :destroy
|
197
217
|
#
|
198
|
-
#
|
218
|
+
# before_destroy :log_children, prepend: true
|
199
219
|
#
|
200
|
-
#
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
220
|
+
# private
|
221
|
+
# def log_children
|
222
|
+
# # Child processing
|
223
|
+
# end
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# This way, the +before_destroy+ gets executed before the <tt>dependent: :destroy</tt> is called, and the data is still available.
|
204
227
|
#
|
205
|
-
# == Transactions
|
228
|
+
# == \Transactions
|
206
229
|
#
|
207
|
-
# The entire callback chain of a
|
208
|
-
# within a transaction. That includes <tt>after_*</tt> hooks.
|
209
|
-
# goes fine a COMMIT is executed once the chain has been completed.
|
230
|
+
# The entire callback chain of a {#save}[rdoc-ref:Persistence#save], {#save!}[rdoc-ref:Persistence#save!],
|
231
|
+
# or {#destroy}[rdoc-ref:Persistence#destroy] call runs within a transaction. That includes <tt>after_*</tt> hooks.
|
232
|
+
# If everything goes fine a COMMIT is executed once the chain has been completed.
|
210
233
|
#
|
211
234
|
# If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued. You
|
212
235
|
# can also trigger a ROLLBACK raising an exception in any of the callbacks,
|
213
236
|
# including <tt>after_*</tt> hooks. Note, however, that in that case the client
|
214
|
-
# needs to be aware of it because an ordinary
|
237
|
+
# needs to be aware of it because an ordinary {#save}[rdoc-ref:Persistence#save] will raise such exception
|
215
238
|
# instead of quietly returning +false+.
|
216
239
|
#
|
217
240
|
# == Debugging callbacks
|
218
|
-
#
|
219
|
-
# The callback chain is accessible via the <tt>_*_callbacks</tt> method on an object.
|
241
|
+
#
|
242
|
+
# The callback chain is accessible via the <tt>_*_callbacks</tt> method on an object. Active Model \Callbacks support
|
220
243
|
# <tt>:before</tt>, <tt>:after</tt> and <tt>:around</tt> as values for the <tt>kind</tt> property. The <tt>kind</tt> property
|
221
244
|
# defines what part of the chain the callback runs in.
|
222
|
-
#
|
223
|
-
# To find all callbacks in the before_save callback chain:
|
224
|
-
#
|
245
|
+
#
|
246
|
+
# To find all callbacks in the before_save callback chain:
|
247
|
+
#
|
225
248
|
# Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }
|
226
|
-
#
|
249
|
+
#
|
227
250
|
# Returns an array of callback objects that form the before_save chain.
|
228
|
-
#
|
251
|
+
#
|
229
252
|
# To further check if the before_save chain contains a proc defined as <tt>rest_when_dead</tt> use the <tt>filter</tt> property of the callback object:
|
230
|
-
#
|
253
|
+
#
|
231
254
|
# Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:rest_when_dead)
|
232
|
-
#
|
255
|
+
#
|
233
256
|
# Returns true or false depending on whether the proc is contained in the before_save callback chain on a Topic model.
|
234
|
-
#
|
257
|
+
#
|
235
258
|
module Callbacks
|
236
259
|
extend ActiveSupport::Concern
|
237
260
|
|
@@ -242,8 +265,11 @@ module ActiveRecord
|
|
242
265
|
:before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
|
243
266
|
]
|
244
267
|
|
268
|
+
module ClassMethods # :nodoc:
|
269
|
+
include ActiveModel::Callbacks
|
270
|
+
end
|
271
|
+
|
245
272
|
included do
|
246
|
-
extend ActiveModel::Callbacks
|
247
273
|
include ActiveModel::Validations::Callbacks
|
248
274
|
|
249
275
|
define_model_callbacks :initialize, :find, :touch, :only => :after
|
@@ -251,25 +277,33 @@ module ActiveRecord
|
|
251
277
|
end
|
252
278
|
|
253
279
|
def destroy #:nodoc:
|
254
|
-
|
280
|
+
@_destroy_callback_already_called ||= false
|
281
|
+
return if @_destroy_callback_already_called
|
282
|
+
@_destroy_callback_already_called = true
|
283
|
+
_run_destroy_callbacks { super }
|
284
|
+
rescue RecordNotDestroyed => e
|
285
|
+
@_association_destroy_exception = e
|
286
|
+
false
|
287
|
+
ensure
|
288
|
+
@_destroy_callback_already_called = false
|
255
289
|
end
|
256
290
|
|
257
291
|
def touch(*) #:nodoc:
|
258
|
-
|
292
|
+
_run_touch_callbacks { super }
|
259
293
|
end
|
260
294
|
|
261
295
|
private
|
262
296
|
|
263
|
-
def create_or_update #:nodoc:
|
264
|
-
|
297
|
+
def create_or_update(*) #:nodoc:
|
298
|
+
_run_save_callbacks { super }
|
265
299
|
end
|
266
300
|
|
267
|
-
def
|
268
|
-
|
301
|
+
def _create_record #:nodoc:
|
302
|
+
_run_create_callbacks { super }
|
269
303
|
end
|
270
304
|
|
271
|
-
def
|
272
|
-
|
305
|
+
def _update_record(*) #:nodoc:
|
306
|
+
_run_update_callbacks { super }
|
273
307
|
end
|
274
308
|
end
|
275
309
|
end
|
@@ -1,41 +1,50 @@
|
|
1
|
-
|
2
|
-
# :stopdoc:
|
3
|
-
module Coders
|
4
|
-
class YAMLColumn
|
5
|
-
RESCUE_ERRORS = [ ArgumentError ]
|
1
|
+
require 'yaml'
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
module ActiveRecord
|
4
|
+
module Coders # :nodoc:
|
5
|
+
class YAMLColumn # :nodoc:
|
10
6
|
|
11
7
|
attr_accessor :object_class
|
12
8
|
|
13
9
|
def initialize(object_class = Object)
|
14
10
|
@object_class = object_class
|
11
|
+
check_arity_of_constructor
|
15
12
|
end
|
16
13
|
|
17
14
|
def dump(obj)
|
15
|
+
return if obj.nil?
|
16
|
+
|
17
|
+
assert_valid_value(obj)
|
18
18
|
YAML.dump obj
|
19
19
|
end
|
20
20
|
|
21
21
|
def load(yaml)
|
22
22
|
return object_class.new if object_class != Object && yaml.nil?
|
23
23
|
return yaml unless yaml.is_a?(String) && yaml =~ /^---/
|
24
|
-
|
25
|
-
|
24
|
+
obj = YAML.load(yaml)
|
25
|
+
|
26
|
+
assert_valid_value(obj)
|
27
|
+
obj ||= object_class.new if object_class != Object
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
obj
|
30
|
+
end
|
31
|
+
|
32
|
+
def assert_valid_value(obj)
|
33
|
+
unless obj.nil? || obj.is_a?(object_class)
|
34
|
+
raise SerializationTypeMismatch,
|
35
|
+
"Attribute was supposed to be a #{object_class}, but was a #{obj.class}. -- #{obj.inspect}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
|
41
|
+
def check_arity_of_constructor
|
42
|
+
begin
|
43
|
+
load(nil)
|
44
|
+
rescue ArgumentError
|
45
|
+
raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
|
36
46
|
end
|
37
47
|
end
|
38
48
|
end
|
39
49
|
end
|
40
|
-
# :startdoc
|
41
50
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module CollectionCacheKey
|
3
|
+
|
4
|
+
def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
|
5
|
+
query_signature = Digest::MD5.hexdigest(collection.to_sql)
|
6
|
+
key = "#{collection.model_name.cache_key}/query-#{query_signature}"
|
7
|
+
|
8
|
+
if collection.loaded?
|
9
|
+
size = collection.size
|
10
|
+
if size > 0
|
11
|
+
timestamp = collection.max_by(×tamp_column).public_send(timestamp_column)
|
12
|
+
end
|
13
|
+
else
|
14
|
+
column_type = type_for_attribute(timestamp_column.to_s)
|
15
|
+
column = "#{connection.quote_table_name(collection.table_name)}.#{connection.quote_column_name(timestamp_column)}"
|
16
|
+
|
17
|
+
query = collection
|
18
|
+
.unscope(:select)
|
19
|
+
.select("COUNT(*) AS #{connection.quote_column_name("size")}", "MAX(#{column}) AS timestamp")
|
20
|
+
.unscope(:order)
|
21
|
+
result = connection.select_one(query)
|
22
|
+
|
23
|
+
if result.blank?
|
24
|
+
size = 0
|
25
|
+
timestamp = nil
|
26
|
+
else
|
27
|
+
size = result["size"]
|
28
|
+
timestamp = column_type.deserialize(result["timestamp"])
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
if timestamp
|
34
|
+
"#{key}-#{size}-#{timestamp.utc.to_s(cache_timestamp_format)}"
|
35
|
+
else
|
36
|
+
"#{key}-#{size}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|