activerecord 4.2.0 → 5.2.8.1
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 +5 -5
- data/CHANGELOG.md +640 -928
- data/MIT-LICENSE +2 -2
- data/README.rdoc +10 -11
- data/examples/performance.rb +32 -31
- data/examples/simple.rb +5 -4
- data/lib/active_record/aggregations.rb +264 -247
- data/lib/active_record/association_relation.rb +24 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +87 -41
- data/lib/active_record/associations/association_scope.rb +106 -132
- data/lib/active_record/associations/belongs_to_association.rb +55 -36
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
- data/lib/active_record/associations/builder/association.rb +29 -38
- data/lib/active_record/associations/builder/belongs_to.rb +77 -30
- data/lib/active_record/associations/builder/collection_association.rb +14 -23
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
- data/lib/active_record/associations/builder/has_many.rb +6 -4
- data/lib/active_record/associations/builder/has_one.rb +13 -6
- data/lib/active_record/associations/builder/singular_association.rb +15 -11
- data/lib/active_record/associations/collection_association.rb +145 -266
- data/lib/active_record/associations/collection_proxy.rb +242 -138
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +35 -75
- data/lib/active_record/associations/has_many_through_association.rb +51 -69
- data/lib/active_record/associations/has_one_association.rb +39 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
- data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
- data/lib/active_record/associations/join_dependency.rb +134 -154
- data/lib/active_record/associations/preloader/association.rb +85 -116
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +83 -93
- data/lib/active_record/associations/singular_association.rb +27 -40
- data/lib/active_record/associations/through_association.rb +48 -23
- data/lib/active_record/associations.rb +1732 -1596
- data/lib/active_record/attribute_assignment.rb +58 -182
- data/lib/active_record/attribute_decorators.rb +39 -15
- data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
- data/lib/active_record/attribute_methods/dirty.rb +94 -125
- data/lib/active_record/attribute_methods/primary_key.rb +86 -71
- data/lib/active_record/attribute_methods/query.rb +4 -2
- data/lib/active_record/attribute_methods/read.rb +45 -63
- data/lib/active_record/attribute_methods/serialization.rb +40 -20
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
- data/lib/active_record/attribute_methods/write.rb +31 -46
- data/lib/active_record/attribute_methods.rb +170 -117
- data/lib/active_record/attributes.rb +201 -74
- data/lib/active_record/autosave_association.rb +118 -45
- data/lib/active_record/base.rb +60 -48
- data/lib/active_record/callbacks.rb +97 -57
- data/lib/active_record/coders/json.rb +3 -1
- data/lib/active_record/coders/yaml_column.rb +37 -13
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
- data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
- data/lib/active_record/connection_adapters/column.rb +50 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
- data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +40 -27
- data/lib/active_record/core.rb +205 -202
- data/lib/active_record/counter_cache.rb +80 -37
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +136 -90
- data/lib/active_record/errors.rb +180 -52
- data/lib/active_record/explain.rb +23 -11
- data/lib/active_record/explain_registry.rb +4 -2
- data/lib/active_record/explain_subscriber.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +193 -135
- data/lib/active_record/gem_version.rb +5 -3
- data/lib/active_record/inheritance.rb +148 -112
- data/lib/active_record/integration.rb +70 -28
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +92 -98
- data/lib/active_record/locking/pessimistic.rb +15 -3
- data/lib/active_record/log_subscriber.rb +95 -33
- data/lib/active_record/migration/command_recorder.rb +133 -90
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +8 -6
- data/lib/active_record/migration.rb +594 -267
- data/lib/active_record/model_schema.rb +292 -111
- data/lib/active_record/nested_attributes.rb +266 -214
- data/lib/active_record/no_touching.rb +8 -2
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +350 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +117 -35
- data/lib/active_record/railties/console_sandbox.rb +2 -0
- data/lib/active_record/railties/controller_runtime.rb +9 -3
- data/lib/active_record/railties/databases.rake +160 -174
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +447 -288
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +204 -55
- data/lib/active_record/relation/calculations.rb +259 -244
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +290 -253
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +91 -68
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
- data/lib/active_record/relation/predicate_builder.rb +118 -92
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +446 -389
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +18 -16
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/relation.rb +287 -339
- data/lib/active_record/result.rb +54 -36
- data/lib/active_record/runtime_registry.rb +6 -4
- data/lib/active_record/sanitization.rb +155 -124
- data/lib/active_record/schema.rb +30 -24
- data/lib/active_record/schema_dumper.rb +91 -87
- data/lib/active_record/schema_migration.rb +19 -19
- data/lib/active_record/scoping/default.rb +102 -84
- data/lib/active_record/scoping/named.rb +81 -32
- data/lib/active_record/scoping.rb +45 -26
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/statement_cache.rb +45 -35
- data/lib/active_record/store.rb +42 -36
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +136 -95
- data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
- data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
- data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
- data/lib/active_record/timestamp.rb +70 -38
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +208 -123
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +4 -41
- data/lib/active_record/type/date_time.rb +4 -38
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +30 -15
- data/lib/active_record/type/text.rb +2 -2
- data/lib/active_record/type/time.rb +11 -16
- data/lib/active_record/type/type_map.rb +15 -17
- data/lib/active_record/type/unsigned_integer.rb +9 -7
- data/lib/active_record/type.rb +79 -23
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +13 -4
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +14 -13
- data/lib/active_record/validations/uniqueness.rb +41 -32
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +36 -21
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
- data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
- data/lib/rails/generators/active_record/migration.rb +18 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
- data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +77 -53
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute.rb +0 -149
- data/lib/active_record/attribute_set/builder.rb +0 -86
- data/lib/active_record/attribute_set.rb +0 -77
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -30
- data/lib/active_record/type/decimal.rb +0 -40
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -55
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -36
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -101
- /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# ActiveRecord::Suppressor prevents the receiver from being saved during
|
5
|
+
# a given block.
|
6
|
+
#
|
7
|
+
# For example, here's a pattern of creating notifications when new comments
|
8
|
+
# are posted. (The notification may in turn trigger an email, a push
|
9
|
+
# notification, or just appear in the UI somewhere):
|
10
|
+
#
|
11
|
+
# class Comment < ActiveRecord::Base
|
12
|
+
# belongs_to :commentable, polymorphic: true
|
13
|
+
# after_create -> { Notification.create! comment: self,
|
14
|
+
# recipients: commentable.recipients }
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# That's what you want the bulk of the time. New comment creates a new
|
18
|
+
# Notification. But there may well be off cases, like copying a commentable
|
19
|
+
# and its comments, where you don't want that. So you'd have a concern
|
20
|
+
# something like this:
|
21
|
+
#
|
22
|
+
# module Copyable
|
23
|
+
# def copy_to(destination)
|
24
|
+
# Notification.suppress do
|
25
|
+
# # Copy logic that creates new comments that we do not want
|
26
|
+
# # triggering notifications.
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
module Suppressor
|
31
|
+
extend ActiveSupport::Concern
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
def suppress(&block)
|
35
|
+
previous_state = SuppressorRegistry.suppressed[name]
|
36
|
+
SuppressorRegistry.suppressed[name] = true
|
37
|
+
yield
|
38
|
+
ensure
|
39
|
+
SuppressorRegistry.suppressed[name] = previous_state
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def save(*) # :nodoc:
|
44
|
+
SuppressorRegistry.suppressed[self.class.name] ? true : super
|
45
|
+
end
|
46
|
+
|
47
|
+
def save!(*) # :nodoc:
|
48
|
+
SuppressorRegistry.suppressed[self.class.name] ? true : super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class SuppressorRegistry # :nodoc:
|
53
|
+
extend ActiveSupport::PerThreadRegistry
|
54
|
+
|
55
|
+
attr_reader :suppressed
|
56
|
+
|
57
|
+
def initialize
|
58
|
+
@suppressed = {}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class TableMetadata # :nodoc:
|
5
|
+
delegate :foreign_type, :foreign_key, :join_primary_key, :join_foreign_key, to: :association, prefix: true
|
6
|
+
|
7
|
+
def initialize(klass, arel_table, association = nil)
|
8
|
+
@klass = klass
|
9
|
+
@arel_table = arel_table
|
10
|
+
@association = association
|
11
|
+
end
|
12
|
+
|
13
|
+
def resolve_column_aliases(hash)
|
14
|
+
new_hash = hash.dup
|
15
|
+
hash.each do |key, _|
|
16
|
+
if (key.is_a?(Symbol)) && klass.attribute_alias?(key)
|
17
|
+
new_hash[klass.attribute_alias(key)] = new_hash.delete(key)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
new_hash
|
21
|
+
end
|
22
|
+
|
23
|
+
def arel_attribute(column_name)
|
24
|
+
if klass
|
25
|
+
klass.arel_attribute(column_name, arel_table)
|
26
|
+
else
|
27
|
+
arel_table[column_name]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def type(column_name)
|
32
|
+
if klass
|
33
|
+
klass.type_for_attribute(column_name)
|
34
|
+
else
|
35
|
+
Type.default_value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_column?(column_name)
|
40
|
+
klass && klass.columns_hash.key?(column_name.to_s)
|
41
|
+
end
|
42
|
+
|
43
|
+
def associated_with?(association_name)
|
44
|
+
klass && klass._reflect_on_association(association_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def associated_table(table_name)
|
48
|
+
association = klass._reflect_on_association(table_name) || klass._reflect_on_association(table_name.to_s.singularize)
|
49
|
+
|
50
|
+
if !association && table_name == arel_table.name
|
51
|
+
return self
|
52
|
+
elsif association && !association.polymorphic?
|
53
|
+
association_klass = association.klass
|
54
|
+
arel_table = association_klass.arel_table.alias(table_name)
|
55
|
+
else
|
56
|
+
type_caster = TypeCaster::Connection.new(klass, table_name)
|
57
|
+
association_klass = nil
|
58
|
+
arel_table = Arel::Table.new(table_name, type_caster: type_caster)
|
59
|
+
end
|
60
|
+
|
61
|
+
TableMetadata.new(association_klass, arel_table, association)
|
62
|
+
end
|
63
|
+
|
64
|
+
def polymorphic_association?
|
65
|
+
association && association.polymorphic?
|
66
|
+
end
|
67
|
+
|
68
|
+
def aggregated_with?(aggregation_name)
|
69
|
+
klass && reflect_on_aggregation(aggregation_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
def reflect_on_aggregation(aggregation_name)
|
73
|
+
klass.reflect_on_aggregation(aggregation_name)
|
74
|
+
end
|
75
|
+
|
76
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
77
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
78
|
+
protected
|
79
|
+
|
80
|
+
attr_reader :klass, :arel_table, :association
|
81
|
+
end
|
82
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Tasks # :nodoc:
|
5
5
|
class DatabaseAlreadyExists < StandardError; end # :nodoc:
|
6
6
|
class DatabaseNotSupported < StandardError; end # :nodoc:
|
7
7
|
|
8
|
-
#
|
8
|
+
# ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
|
9
9
|
# logic behind common tasks used to manage database and migrations.
|
10
10
|
#
|
11
11
|
# The tasks defined here are used with Rake tasks provided by Active Record.
|
@@ -18,15 +18,15 @@ module ActiveRecord
|
|
18
18
|
#
|
19
19
|
# The possible config values are:
|
20
20
|
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
21
|
+
# * +env+: current environment (like Rails.env).
|
22
|
+
# * +database_configuration+: configuration of your databases (as in +config/database.yml+).
|
23
|
+
# * +db_dir+: your +db+ directory.
|
24
|
+
# * +fixtures_path+: a path to fixtures directory.
|
25
|
+
# * +migrations_paths+: a list of paths to directories with migrations.
|
26
|
+
# * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
|
27
|
+
# * +root+: a path to the root of the application.
|
28
28
|
#
|
29
|
-
# Example usage of
|
29
|
+
# Example usage of DatabaseTasks outside Rails could look as such:
|
30
30
|
#
|
31
31
|
# include ActiveRecord::Tasks
|
32
32
|
# DatabaseTasks.database_configuration = YAML.load_file('my_database_config.yml')
|
@@ -35,36 +35,62 @@ module ActiveRecord
|
|
35
35
|
#
|
36
36
|
# DatabaseTasks.create_current('production')
|
37
37
|
module DatabaseTasks
|
38
|
+
##
|
39
|
+
# :singleton-method:
|
40
|
+
# Extra flags passed to database CLI tool (mysqldump/pg_dump) when calling db:structure:dump
|
41
|
+
mattr_accessor :structure_dump_flags, instance_accessor: false
|
42
|
+
|
43
|
+
##
|
44
|
+
# :singleton-method:
|
45
|
+
# Extra flags passed to database CLI tool when calling db:structure:load
|
46
|
+
mattr_accessor :structure_load_flags, instance_accessor: false
|
47
|
+
|
38
48
|
extend self
|
39
49
|
|
40
50
|
attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader
|
41
51
|
attr_accessor :database_configuration
|
42
52
|
|
43
|
-
LOCAL_HOSTS
|
53
|
+
LOCAL_HOSTS = ["127.0.0.1", "localhost"]
|
54
|
+
|
55
|
+
def check_protected_environments!
|
56
|
+
unless ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]
|
57
|
+
current = ActiveRecord::Base.connection.migration_context.current_environment
|
58
|
+
stored = ActiveRecord::Base.connection.migration_context.last_stored_environment
|
59
|
+
|
60
|
+
if ActiveRecord::Base.connection.migration_context.protected_environment?
|
61
|
+
raise ActiveRecord::ProtectedEnvironmentError.new(stored)
|
62
|
+
end
|
63
|
+
|
64
|
+
if stored && stored != current
|
65
|
+
raise ActiveRecord::EnvironmentMismatchError.new(current: current, stored: stored)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
rescue ActiveRecord::NoDatabaseError
|
69
|
+
end
|
44
70
|
|
45
71
|
def register_task(pattern, task)
|
46
72
|
@tasks ||= {}
|
47
73
|
@tasks[pattern] = task
|
48
74
|
end
|
49
75
|
|
50
|
-
register_task(/mysql/, ActiveRecord::Tasks::MySQLDatabaseTasks)
|
51
|
-
register_task(/postgresql/, ActiveRecord::Tasks::PostgreSQLDatabaseTasks)
|
52
|
-
register_task(/sqlite/, ActiveRecord::Tasks::SQLiteDatabaseTasks)
|
76
|
+
register_task(/mysql/, "ActiveRecord::Tasks::MySQLDatabaseTasks")
|
77
|
+
register_task(/postgresql/, "ActiveRecord::Tasks::PostgreSQLDatabaseTasks")
|
78
|
+
register_task(/sqlite/, "ActiveRecord::Tasks::SQLiteDatabaseTasks")
|
53
79
|
|
54
80
|
def db_dir
|
55
81
|
@db_dir ||= Rails.application.config.paths["db"].first
|
56
82
|
end
|
57
83
|
|
58
84
|
def migrations_paths
|
59
|
-
@migrations_paths ||= Rails.application.paths[
|
85
|
+
@migrations_paths ||= Rails.application.paths["db/migrate"].to_a
|
60
86
|
end
|
61
87
|
|
62
88
|
def fixtures_path
|
63
|
-
@fixtures_path ||= if ENV[
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
89
|
+
@fixtures_path ||= if ENV["FIXTURES_PATH"]
|
90
|
+
File.join(root, ENV["FIXTURES_PATH"])
|
91
|
+
else
|
92
|
+
File.join(root, "test", "fixtures")
|
93
|
+
end
|
68
94
|
end
|
69
95
|
|
70
96
|
def root
|
@@ -80,7 +106,7 @@ module ActiveRecord
|
|
80
106
|
end
|
81
107
|
|
82
108
|
def current_config(options = {})
|
83
|
-
options.reverse_merge! :
|
109
|
+
options.reverse_merge! env: env
|
84
110
|
if options.has_key?(:config)
|
85
111
|
@current_config = options[:config]
|
86
112
|
else
|
@@ -90,16 +116,22 @@ module ActiveRecord
|
|
90
116
|
|
91
117
|
def create(*arguments)
|
92
118
|
configuration = arguments.first
|
93
|
-
class_for_adapter(configuration[
|
119
|
+
class_for_adapter(configuration["adapter"]).new(*arguments).create
|
120
|
+
$stdout.puts "Created database '#{configuration['database']}'"
|
94
121
|
rescue DatabaseAlreadyExists
|
95
|
-
$stderr.puts "#{configuration['database']} already exists"
|
122
|
+
$stderr.puts "Database '#{configuration['database']}' already exists"
|
96
123
|
rescue Exception => error
|
97
|
-
$stderr.puts error
|
98
|
-
$stderr.puts "Couldn't create database
|
124
|
+
$stderr.puts error
|
125
|
+
$stderr.puts "Couldn't create '#{configuration['database']}' database. Please check your configuration."
|
126
|
+
raise
|
99
127
|
end
|
100
128
|
|
101
129
|
def create_all
|
130
|
+
old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
|
102
131
|
each_local_configuration { |configuration| create configuration }
|
132
|
+
if old_pool
|
133
|
+
ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec.to_hash)
|
134
|
+
end
|
103
135
|
end
|
104
136
|
|
105
137
|
def create_current(environment = env)
|
@@ -111,12 +143,14 @@ module ActiveRecord
|
|
111
143
|
|
112
144
|
def drop(*arguments)
|
113
145
|
configuration = arguments.first
|
114
|
-
class_for_adapter(configuration[
|
146
|
+
class_for_adapter(configuration["adapter"]).new(*arguments).drop
|
147
|
+
$stdout.puts "Dropped database '#{configuration['database']}'"
|
115
148
|
rescue ActiveRecord::NoDatabaseError
|
116
149
|
$stderr.puts "Database '#{configuration['database']}' does not exist"
|
117
150
|
rescue Exception => error
|
118
|
-
$stderr.puts error
|
119
|
-
$stderr.puts "Couldn't drop #{configuration['database']}"
|
151
|
+
$stderr.puts error
|
152
|
+
$stderr.puts "Couldn't drop database '#{configuration['database']}'"
|
153
|
+
raise
|
120
154
|
end
|
121
155
|
|
122
156
|
def drop_all
|
@@ -130,24 +164,36 @@ module ActiveRecord
|
|
130
164
|
end
|
131
165
|
|
132
166
|
def migrate
|
133
|
-
|
134
|
-
|
135
|
-
|
167
|
+
check_target_version
|
168
|
+
|
169
|
+
verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
|
170
|
+
scope = ENV["SCOPE"]
|
136
171
|
verbose_was, Migration.verbose = Migration.verbose, verbose
|
137
|
-
|
172
|
+
Base.connection.migration_context.migrate(target_version) do |migration|
|
138
173
|
scope.blank? || scope == migration.scope
|
139
174
|
end
|
175
|
+
ActiveRecord::Base.clear_cache!
|
140
176
|
ensure
|
141
177
|
Migration.verbose = verbose_was
|
142
178
|
end
|
143
179
|
|
180
|
+
def check_target_version
|
181
|
+
if target_version && !(Migration::MigrationFilenameRegexp.match?(ENV["VERSION"]) || /\A\d+\z/.match?(ENV["VERSION"]))
|
182
|
+
raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def target_version
|
187
|
+
ENV["VERSION"].to_i if ENV["VERSION"] && !ENV["VERSION"].empty?
|
188
|
+
end
|
189
|
+
|
144
190
|
def charset_current(environment = env)
|
145
191
|
charset ActiveRecord::Base.configurations[environment]
|
146
192
|
end
|
147
193
|
|
148
194
|
def charset(*arguments)
|
149
195
|
configuration = arguments.first
|
150
|
-
class_for_adapter(configuration[
|
196
|
+
class_for_adapter(configuration["adapter"]).new(*arguments).charset
|
151
197
|
end
|
152
198
|
|
153
199
|
def collation_current(environment = env)
|
@@ -156,11 +202,11 @@ module ActiveRecord
|
|
156
202
|
|
157
203
|
def collation(*arguments)
|
158
204
|
configuration = arguments.first
|
159
|
-
class_for_adapter(configuration[
|
205
|
+
class_for_adapter(configuration["adapter"]).new(*arguments).collation
|
160
206
|
end
|
161
207
|
|
162
208
|
def purge(configuration)
|
163
|
-
class_for_adapter(configuration[
|
209
|
+
class_for_adapter(configuration["adapter"]).new(configuration).purge
|
164
210
|
end
|
165
211
|
|
166
212
|
def purge_all
|
@@ -179,68 +225,53 @@ module ActiveRecord
|
|
179
225
|
def structure_dump(*arguments)
|
180
226
|
configuration = arguments.first
|
181
227
|
filename = arguments.delete_at 1
|
182
|
-
class_for_adapter(configuration[
|
228
|
+
class_for_adapter(configuration["adapter"]).new(*arguments).structure_dump(filename, structure_dump_flags)
|
183
229
|
end
|
184
230
|
|
185
231
|
def structure_load(*arguments)
|
186
232
|
configuration = arguments.first
|
187
233
|
filename = arguments.delete_at 1
|
188
|
-
class_for_adapter(configuration[
|
189
|
-
end
|
190
|
-
|
191
|
-
def load_schema(format = ActiveRecord::Base.schema_format, file = nil)
|
192
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
193
|
-
This method will act on a specific connection in the future.
|
194
|
-
To act on the current connection, use `load_schema_current` instead.
|
195
|
-
MSG
|
196
|
-
|
197
|
-
load_schema_current(format, file)
|
234
|
+
class_for_adapter(configuration["adapter"]).new(*arguments).structure_load(filename, structure_load_flags)
|
198
235
|
end
|
199
236
|
|
200
|
-
def
|
201
|
-
case format
|
202
|
-
when :ruby
|
203
|
-
File.join(db_dir, "schema.rb")
|
204
|
-
when :sql
|
205
|
-
File.join(db_dir, "structure.sql")
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# This method is the successor of +load_schema+. We should rename it
|
210
|
-
# after +load_schema+ went through a deprecation cycle. (Rails > 4.2)
|
211
|
-
def load_schema_for(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
|
237
|
+
def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env) # :nodoc:
|
212
238
|
file ||= schema_file(format)
|
213
239
|
|
240
|
+
check_schema_file(file)
|
241
|
+
ActiveRecord::Base.establish_connection(configuration)
|
242
|
+
|
214
243
|
case format
|
215
244
|
when :ruby
|
216
|
-
check_schema_file(file)
|
217
|
-
ActiveRecord::Base.establish_connection(configuration)
|
218
245
|
load(file)
|
219
246
|
when :sql
|
220
|
-
check_schema_file(file)
|
221
247
|
structure_load(configuration, file)
|
222
248
|
else
|
223
249
|
raise ArgumentError, "unknown format #{format.inspect}"
|
224
250
|
end
|
251
|
+
ActiveRecord::InternalMetadata.create_table
|
252
|
+
ActiveRecord::InternalMetadata[:environment] = environment
|
225
253
|
end
|
226
254
|
|
227
|
-
def
|
228
|
-
|
229
|
-
|
255
|
+
def schema_file(format = ActiveRecord::Base.schema_format)
|
256
|
+
case format
|
257
|
+
when :ruby
|
258
|
+
File.join(db_dir, "schema.rb")
|
259
|
+
when :sql
|
260
|
+
File.join(db_dir, "structure.sql")
|
230
261
|
end
|
231
262
|
end
|
232
263
|
|
233
264
|
def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
|
234
|
-
each_current_configuration(environment) { |configuration|
|
235
|
-
|
265
|
+
each_current_configuration(environment) { |configuration, configuration_environment|
|
266
|
+
load_schema configuration, format, file, configuration_environment
|
236
267
|
}
|
237
268
|
ActiveRecord::Base.establish_connection(environment.to_sym)
|
238
269
|
end
|
239
270
|
|
240
271
|
def check_schema_file(filename)
|
241
272
|
unless File.exist?(filename)
|
242
|
-
message = %{#{filename} doesn't exist yet. Run `
|
243
|
-
message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails)
|
273
|
+
message = %{#{filename} doesn't exist yet. Run `rails db:migrate` to create it, then try again.}.dup
|
274
|
+
message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails.root)
|
244
275
|
Kernel.abort message
|
245
276
|
end
|
246
277
|
end
|
@@ -249,48 +280,58 @@ module ActiveRecord
|
|
249
280
|
if seed_loader
|
250
281
|
seed_loader.load_seed
|
251
282
|
else
|
252
|
-
raise "You tried to load seed data, but no seed loader is specified. Please specify seed "
|
253
|
-
"loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n"
|
283
|
+
raise "You tried to load seed data, but no seed loader is specified. Please specify seed " \
|
284
|
+
"loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n" \
|
254
285
|
"Seed loader should respond to load_seed method"
|
255
286
|
end
|
256
287
|
end
|
257
288
|
|
289
|
+
# Dumps the schema cache in YAML format for the connection into the file
|
290
|
+
#
|
291
|
+
# ==== Examples:
|
292
|
+
# ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.connection, "tmp/schema_dump.yaml")
|
293
|
+
def dump_schema_cache(conn, filename)
|
294
|
+
conn.schema_cache.clear!
|
295
|
+
conn.data_sources.each { |table| conn.schema_cache.add(table) }
|
296
|
+
open(filename, "wb") { |f| f.write(YAML.dump(conn.schema_cache)) }
|
297
|
+
end
|
298
|
+
|
258
299
|
private
|
259
300
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
301
|
+
def class_for_adapter(adapter)
|
302
|
+
_key, task = @tasks.each_pair.detect { |pattern, _task| adapter[pattern] }
|
303
|
+
unless task
|
304
|
+
raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
|
305
|
+
end
|
306
|
+
task.is_a?(String) ? task.constantize : task
|
264
307
|
end
|
265
|
-
@tasks[key]
|
266
|
-
end
|
267
308
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
309
|
+
def each_current_configuration(environment)
|
310
|
+
environments = [environment]
|
311
|
+
environments << "test" if environment == "development"
|
312
|
+
|
313
|
+
ActiveRecord::Base.configurations.slice(*environments).each do |configuration_environment, configuration|
|
314
|
+
next unless configuration["database"]
|
272
315
|
|
273
|
-
|
274
|
-
|
275
|
-
yield configuration unless configuration['database'].blank?
|
316
|
+
yield configuration, configuration_environment
|
317
|
+
end
|
276
318
|
end
|
277
|
-
end
|
278
319
|
|
279
|
-
|
280
|
-
|
281
|
-
|
320
|
+
def each_local_configuration
|
321
|
+
ActiveRecord::Base.configurations.each_value do |configuration|
|
322
|
+
next unless configuration["database"]
|
282
323
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
324
|
+
if local_database?(configuration)
|
325
|
+
yield configuration
|
326
|
+
else
|
327
|
+
$stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host."
|
328
|
+
end
|
287
329
|
end
|
288
330
|
end
|
289
|
-
end
|
290
331
|
|
291
|
-
|
292
|
-
|
293
|
-
|
332
|
+
def local_database?(configuration)
|
333
|
+
configuration["host"].blank? || LOCAL_HOSTS.include?(configuration["host"])
|
334
|
+
end
|
294
335
|
end
|
295
336
|
end
|
296
337
|
end
|