activerecord 4.2.9 → 5.2.8
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 +614 -1572
- 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 +263 -249
- data/lib/active_record/association_relation.rb +11 -6
- data/lib/active_record/associations/alias_tracker.rb +29 -35
- data/lib/active_record/associations/association.rb +77 -43
- data/lib/active_record/associations/association_scope.rb +106 -133
- data/lib/active_record/associations/belongs_to_association.rb +52 -41
- 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 +9 -22
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -35
- 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 +139 -280
- data/lib/active_record/associations/collection_proxy.rb +231 -133
- data/lib/active_record/associations/foreign_association.rb +3 -1
- data/lib/active_record/associations/has_many_association.rb +34 -89
- data/lib/active_record/associations/has_many_through_association.rb +49 -76
- data/lib/active_record/associations/has_one_association.rb +38 -24
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +40 -89
- 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 +133 -159
- data/lib/active_record/associations/preloader/association.rb +85 -120
- data/lib/active_record/associations/preloader/through_association.rb +85 -74
- data/lib/active_record/associations/preloader.rb +81 -91
- data/lib/active_record/associations/singular_association.rb +27 -34
- data/lib/active_record/associations/through_association.rb +38 -18
- data/lib/active_record/associations.rb +1732 -1597
- 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 +10 -8
- data/lib/active_record/attribute_methods/dirty.rb +94 -135
- 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 +58 -36
- data/lib/active_record/attribute_methods/write.rb +30 -45
- data/lib/active_record/attribute_methods.rb +166 -109
- data/lib/active_record/attributes.rb +201 -82
- data/lib/active_record/autosave_association.rb +94 -36
- data/lib/active_record/base.rb +57 -44
- 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 +24 -12
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -290
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +237 -90
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +71 -21
- data/lib/active_record/connection_adapters/abstract/quoting.rb +118 -52
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +318 -217
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +570 -228
- data/lib/active_record/connection_adapters/abstract/transaction.rb +138 -70
- data/lib/active_record/connection_adapters/abstract_adapter.rb +325 -202
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +542 -593
- 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 +41 -188
- data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +45 -114
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -58
- 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 +4 -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 -22
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -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 -5
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +55 -53
- 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 +462 -284
- 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 +432 -323
- 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 -308
- 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 +178 -198
- data/lib/active_record/counter_cache.rb +79 -36
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +87 -105
- data/lib/active_record/enum.rb +135 -88
- data/lib/active_record/errors.rb +179 -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 +10 -5
- data/lib/active_record/fixture_set/file.rb +35 -9
- data/lib/active_record/fixtures.rb +188 -132
- data/lib/active_record/gem_version.rb +4 -2
- 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 +21 -3
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +88 -96
- 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 +581 -282
- data/lib/active_record/model_schema.rb +290 -111
- data/lib/active_record/nested_attributes.rb +264 -222
- data/lib/active_record/no_touching.rb +7 -1
- data/lib/active_record/null_relation.rb +24 -37
- data/lib/active_record/persistence.rb +347 -119
- data/lib/active_record/query_cache.rb +13 -24
- data/lib/active_record/querying.rb +19 -17
- data/lib/active_record/railtie.rb +94 -32
- 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 +149 -156
- data/lib/active_record/readonly_attributes.rb +5 -4
- data/lib/active_record/reflection.rb +414 -267
- 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 +256 -248
- data/lib/active_record/relation/delegation.rb +67 -60
- data/lib/active_record/relation/finder_methods.rb +288 -239
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +86 -86
- data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -24
- 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 +116 -119
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +448 -393
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -13
- 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 -340
- 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 -16
- data/lib/active_record/scoping/default.rb +102 -85
- 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 +134 -96
- data/lib/active_record/tasks/mysql_database_tasks.rb +56 -100
- data/lib/active_record/tasks/postgresql_database_tasks.rb +83 -41
- 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 +199 -124
- 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 -45
- data/lib/active_record/type/date_time.rb +4 -49
- data/lib/active_record/type/decimal_without_scale.rb +6 -2
- data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
- 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 +24 -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 +40 -41
- data/lib/active_record/validations.rb +38 -35
- data/lib/active_record/version.rb +3 -1
- data/lib/active_record.rb +34 -22
- 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 -3
- data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -1
- 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/model/templates/{module.rb → module.rb.tt} +0 -0
- data/lib/rails/generators/active_record.rb +7 -5
- metadata +72 -50
- 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 -163
- data/lib/active_record/attribute_set/builder.rb +0 -106
- data/lib/active_record/attribute_set.rb +0 -81
- 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 -31
- data/lib/active_record/type/decimal.rb +0 -64
- 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 -59
- 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 -40
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/value.rb +0 -110
@@ -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,13 +164,12 @@ module ActiveRecord
|
|
130
164
|
end
|
131
165
|
|
132
166
|
def migrate
|
133
|
-
|
167
|
+
check_target_version
|
134
168
|
|
135
|
-
verbose = ENV["VERBOSE"] ? ENV["VERBOSE"]
|
136
|
-
|
137
|
-
scope = ENV['SCOPE']
|
169
|
+
verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
|
170
|
+
scope = ENV["SCOPE"]
|
138
171
|
verbose_was, Migration.verbose = Migration.verbose, verbose
|
139
|
-
|
172
|
+
Base.connection.migration_context.migrate(target_version) do |migration|
|
140
173
|
scope.blank? || scope == migration.scope
|
141
174
|
end
|
142
175
|
ActiveRecord::Base.clear_cache!
|
@@ -144,13 +177,23 @@ module ActiveRecord
|
|
144
177
|
Migration.verbose = verbose_was
|
145
178
|
end
|
146
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
|
+
|
147
190
|
def charset_current(environment = env)
|
148
191
|
charset ActiveRecord::Base.configurations[environment]
|
149
192
|
end
|
150
193
|
|
151
194
|
def charset(*arguments)
|
152
195
|
configuration = arguments.first
|
153
|
-
class_for_adapter(configuration[
|
196
|
+
class_for_adapter(configuration["adapter"]).new(*arguments).charset
|
154
197
|
end
|
155
198
|
|
156
199
|
def collation_current(environment = env)
|
@@ -159,11 +202,11 @@ module ActiveRecord
|
|
159
202
|
|
160
203
|
def collation(*arguments)
|
161
204
|
configuration = arguments.first
|
162
|
-
class_for_adapter(configuration[
|
205
|
+
class_for_adapter(configuration["adapter"]).new(*arguments).collation
|
163
206
|
end
|
164
207
|
|
165
208
|
def purge(configuration)
|
166
|
-
class_for_adapter(configuration[
|
209
|
+
class_for_adapter(configuration["adapter"]).new(configuration).purge
|
167
210
|
end
|
168
211
|
|
169
212
|
def purge_all
|
@@ -182,68 +225,53 @@ module ActiveRecord
|
|
182
225
|
def structure_dump(*arguments)
|
183
226
|
configuration = arguments.first
|
184
227
|
filename = arguments.delete_at 1
|
185
|
-
class_for_adapter(configuration[
|
228
|
+
class_for_adapter(configuration["adapter"]).new(*arguments).structure_dump(filename, structure_dump_flags)
|
186
229
|
end
|
187
230
|
|
188
231
|
def structure_load(*arguments)
|
189
232
|
configuration = arguments.first
|
190
233
|
filename = arguments.delete_at 1
|
191
|
-
class_for_adapter(configuration[
|
192
|
-
end
|
193
|
-
|
194
|
-
def load_schema(format = ActiveRecord::Base.schema_format, file = nil)
|
195
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
196
|
-
This method will act on a specific connection in the future.
|
197
|
-
To act on the current connection, use `load_schema_current` instead.
|
198
|
-
MSG
|
199
|
-
|
200
|
-
load_schema_current(format, file)
|
201
|
-
end
|
202
|
-
|
203
|
-
def schema_file(format = ActiveRecord::Base.schema_format)
|
204
|
-
case format
|
205
|
-
when :ruby
|
206
|
-
File.join(db_dir, "schema.rb")
|
207
|
-
when :sql
|
208
|
-
File.join(db_dir, "structure.sql")
|
209
|
-
end
|
234
|
+
class_for_adapter(configuration["adapter"]).new(*arguments).structure_load(filename, structure_load_flags)
|
210
235
|
end
|
211
236
|
|
212
|
-
|
213
|
-
# after +load_schema+ went through a deprecation cycle. (Rails > 4.2)
|
214
|
-
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:
|
215
238
|
file ||= schema_file(format)
|
216
239
|
|
240
|
+
check_schema_file(file)
|
241
|
+
ActiveRecord::Base.establish_connection(configuration)
|
242
|
+
|
217
243
|
case format
|
218
244
|
when :ruby
|
219
|
-
check_schema_file(file)
|
220
|
-
ActiveRecord::Base.establish_connection(configuration)
|
221
245
|
load(file)
|
222
246
|
when :sql
|
223
|
-
check_schema_file(file)
|
224
247
|
structure_load(configuration, file)
|
225
248
|
else
|
226
249
|
raise ArgumentError, "unknown format #{format.inspect}"
|
227
250
|
end
|
251
|
+
ActiveRecord::InternalMetadata.create_table
|
252
|
+
ActiveRecord::InternalMetadata[:environment] = environment
|
228
253
|
end
|
229
254
|
|
230
|
-
def
|
231
|
-
|
232
|
-
|
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")
|
233
261
|
end
|
234
262
|
end
|
235
263
|
|
236
264
|
def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
|
237
|
-
each_current_configuration(environment) { |configuration|
|
238
|
-
|
265
|
+
each_current_configuration(environment) { |configuration, configuration_environment|
|
266
|
+
load_schema configuration, format, file, configuration_environment
|
239
267
|
}
|
240
268
|
ActiveRecord::Base.establish_connection(environment.to_sym)
|
241
269
|
end
|
242
270
|
|
243
271
|
def check_schema_file(filename)
|
244
272
|
unless File.exist?(filename)
|
245
|
-
message = %{#{filename} doesn't exist yet. Run `
|
246
|
-
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)
|
247
275
|
Kernel.abort message
|
248
276
|
end
|
249
277
|
end
|
@@ -252,48 +280,58 @@ module ActiveRecord
|
|
252
280
|
if seed_loader
|
253
281
|
seed_loader.load_seed
|
254
282
|
else
|
255
|
-
raise "You tried to load seed data, but no seed loader is specified. Please specify seed "
|
256
|
-
"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" \
|
257
285
|
"Seed loader should respond to load_seed method"
|
258
286
|
end
|
259
287
|
end
|
260
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
|
+
|
261
299
|
private
|
262
300
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
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
|
267
307
|
end
|
268
|
-
@tasks[key]
|
269
|
-
end
|
270
308
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
environments << 'test' if environment == 'development' && ENV['RAILS_ENV'].nil?
|
309
|
+
def each_current_configuration(environment)
|
310
|
+
environments = [environment]
|
311
|
+
environments << "test" if environment == "development"
|
275
312
|
|
276
|
-
|
277
|
-
|
278
|
-
|
313
|
+
ActiveRecord::Base.configurations.slice(*environments).each do |configuration_environment, configuration|
|
314
|
+
next unless configuration["database"]
|
315
|
+
|
316
|
+
yield configuration, configuration_environment
|
317
|
+
end
|
279
318
|
end
|
280
|
-
end
|
281
319
|
|
282
|
-
|
283
|
-
|
284
|
-
|
320
|
+
def each_local_configuration
|
321
|
+
ActiveRecord::Base.configurations.each_value do |configuration|
|
322
|
+
next unless configuration["database"]
|
285
323
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
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
|
290
329
|
end
|
291
330
|
end
|
292
|
-
end
|
293
331
|
|
294
|
-
|
295
|
-
|
296
|
-
|
332
|
+
def local_database?(configuration)
|
333
|
+
configuration["host"].blank? || LOCAL_HOSTS.include?(configuration["host"])
|
334
|
+
end
|
297
335
|
end
|
298
336
|
end
|
299
337
|
end
|