activerecord 5.2.6 → 6.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 +4 -4
- data/CHANGELOG.md +609 -622
- data/MIT-LICENSE +3 -1
- data/README.rdoc +4 -2
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations/association.rb +52 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +6 -21
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -10
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/join_dependency.rb +24 -28
- data/lib/active_record/associations/preloader/association.rb +38 -36
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +40 -32
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations.rb +19 -14
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -22
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -53
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +17 -24
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +5 -9
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +5 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +94 -16
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -8
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
- data/lib/active_record/connection_adapters/abstract_adapter.rb +180 -47
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -141
- data/lib/active_record/connection_handling.rb +149 -27
- data/lib/active_record/core.rb +100 -60
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +79 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +37 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +145 -472
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -3
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +10 -2
- data/lib/active_record/locking/optimistic.rb +5 -6
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +75 -0
- data/lib/active_record/migration/command_recorder.rb +50 -6
- data/lib/active_record/migration/compatibility.rb +76 -49
- data/lib/active_record/migration.rb +100 -81
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +228 -24
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +32 -20
- data/lib/active_record/railtie.rb +80 -43
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +196 -46
- data/lib/active_record/reflection.rb +32 -30
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +53 -47
- data/lib/active_record/relation/delegation.rb +26 -43
- data/lib/active_record/relation/finder_methods.rb +13 -26
- data/lib/active_record/relation/merger.rb +11 -20
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +189 -63
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +14 -10
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +310 -80
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +5 -1
- data/lib/active_record/scoping/default.rb +4 -5
- data/lib/active_record/scoping/named.rb +19 -15
- data/lib/active_record/scoping.rb +8 -8
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/table_metadata.rb +10 -17
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +39 -25
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +57 -66
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record.rb +9 -2
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +204 -0
- data/lib/arel/visitors/dot.rb +297 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +157 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +66 -0
- data/lib/arel/visitors/postgresql.rb +110 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +889 -0
- data/lib/arel/visitors/visitor.rb +46 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +51 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +108 -26
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -61,8 +61,9 @@ module ActiveRecord
|
|
61
61
|
# # => "id ASC"
|
62
62
|
def sanitize_sql_for_order(condition)
|
63
63
|
if condition.is_a?(Array) && condition.first.to_s.include?("?")
|
64
|
-
|
65
|
-
|
64
|
+
disallow_raw_sql!(
|
65
|
+
[condition.first],
|
66
|
+
permit: connection.column_name_with_order_matcher
|
66
67
|
)
|
67
68
|
|
68
69
|
# Ensure we aren't dealing with a subclass of String that might
|
@@ -133,44 +134,34 @@ module ActiveRecord
|
|
133
134
|
end
|
134
135
|
end
|
135
136
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
# Given:
|
142
|
-
#
|
143
|
-
# class Person < ActiveRecord::Base
|
144
|
-
# composed_of :address, class_name: "Address",
|
145
|
-
# mapping: [%w(address_street street), %w(address_city city)]
|
146
|
-
# end
|
147
|
-
#
|
148
|
-
# Then:
|
149
|
-
#
|
150
|
-
# { address: Address.new("813 abc st.", "chicago") }
|
151
|
-
# # => { address_street: "813 abc st.", address_city: "chicago" }
|
152
|
-
def expand_hash_conditions_for_aggregates(attrs) # :doc:
|
153
|
-
expanded_attrs = {}
|
154
|
-
attrs.each do |attr, value|
|
155
|
-
if aggregation = reflect_on_aggregation(attr.to_sym)
|
156
|
-
mapping = aggregation.mapping
|
157
|
-
mapping.each do |field_attr, aggregate_attr|
|
158
|
-
expanded_attrs[field_attr] = if value.is_a?(Array)
|
159
|
-
value.map { |it| it.send(aggregate_attr) }
|
160
|
-
elsif mapping.size == 1 && !value.respond_to?(aggregate_attr)
|
161
|
-
value
|
162
|
-
else
|
163
|
-
value.send(aggregate_attr)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
else
|
167
|
-
expanded_attrs[attr] = value
|
168
|
-
end
|
169
|
-
end
|
170
|
-
expanded_attrs
|
137
|
+
def disallow_raw_sql!(args, permit: connection.column_name_matcher) # :nodoc:
|
138
|
+
unexpected = nil
|
139
|
+
args.each do |arg|
|
140
|
+
next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s)
|
141
|
+
(unexpected ||= []) << arg
|
171
142
|
end
|
172
|
-
deprecate :expand_hash_conditions_for_aggregates
|
173
143
|
|
144
|
+
return unless unexpected
|
145
|
+
|
146
|
+
if allow_unsafe_raw_sql == :deprecated
|
147
|
+
ActiveSupport::Deprecation.warn(
|
148
|
+
"Dangerous query method (method whose arguments are used as raw " \
|
149
|
+
"SQL) called with non-attribute argument(s): " \
|
150
|
+
"#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
|
151
|
+
"arguments will be disallowed in Rails 6.1. This method should " \
|
152
|
+
"not be called with user-provided values, such as request " \
|
153
|
+
"parameters or model attributes. Known-safe values can be passed " \
|
154
|
+
"by wrapping them in Arel.sql()."
|
155
|
+
)
|
156
|
+
else
|
157
|
+
raise(ActiveRecord::UnknownAttributeReference,
|
158
|
+
"Query method called with non-attribute argument(s): " +
|
159
|
+
unexpected.map(&:inspect).join(", ")
|
160
|
+
)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
174
165
|
def replace_bind_variables(statement, values)
|
175
166
|
raise_if_bind_arity_mismatch(statement, statement.count("?"), values.size)
|
176
167
|
bound = values.dup
|
@@ -202,10 +193,11 @@ module ActiveRecord
|
|
202
193
|
|
203
194
|
def quote_bound_value(value, c = connection)
|
204
195
|
if value.respond_to?(:map) && !value.acts_like?(:string)
|
205
|
-
|
196
|
+
quoted = value.map { |v| c.quote(v) }
|
197
|
+
if quoted.empty?
|
206
198
|
c.quote(nil)
|
207
199
|
else
|
208
|
-
|
200
|
+
quoted.join(",")
|
209
201
|
end
|
210
202
|
else
|
211
203
|
c.quote(value)
|
data/lib/active_record/schema.rb
CHANGED
@@ -50,21 +50,12 @@ module ActiveRecord
|
|
50
50
|
instance_eval(&block)
|
51
51
|
|
52
52
|
if info[:version].present?
|
53
|
-
|
54
|
-
connection.assume_migrated_upto_version(info[:version]
|
53
|
+
connection.schema_migration.create_table
|
54
|
+
connection.assume_migrated_upto_version(info[:version])
|
55
55
|
end
|
56
56
|
|
57
57
|
ActiveRecord::InternalMetadata.create_table
|
58
58
|
ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
|
59
59
|
end
|
60
|
-
|
61
|
-
private
|
62
|
-
# Returns the migrations paths.
|
63
|
-
#
|
64
|
-
# ActiveRecord::Schema.new.migrations_paths
|
65
|
-
# # => ["db/migrate"] # Rails migration path by default.
|
66
|
-
def migrations_paths
|
67
|
-
ActiveRecord::Migrator.migrations_paths
|
68
|
-
end
|
69
60
|
end
|
70
61
|
end
|
@@ -17,6 +17,12 @@ module ActiveRecord
|
|
17
17
|
# Only strings are accepted if ActiveRecord::Base.schema_format == :sql.
|
18
18
|
cattr_accessor :ignore_tables, default: []
|
19
19
|
|
20
|
+
##
|
21
|
+
# :singleton-method:
|
22
|
+
# Specify a custom regular expression matching foreign keys which name
|
23
|
+
# should not be dumped to db/schema.rb.
|
24
|
+
cattr_accessor :fk_ignore_pattern, default: /^fk_rails_[0-9a-f]{10}$/
|
25
|
+
|
20
26
|
class << self
|
21
27
|
def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
|
22
28
|
connection.create_schema_dumper(generate_options(config)).dump(stream)
|
@@ -41,6 +47,7 @@ module ActiveRecord
|
|
41
47
|
end
|
42
48
|
|
43
49
|
private
|
50
|
+
attr_accessor :table_name
|
44
51
|
|
45
52
|
def initialize(connection, options = {})
|
46
53
|
@connection = connection
|
@@ -65,11 +72,11 @@ module ActiveRecord
|
|
65
72
|
# of editing this file, please use the migrations feature of Active Record to
|
66
73
|
# incrementally modify your database, and then regenerate this schema definition.
|
67
74
|
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
# from scratch.
|
72
|
-
#
|
75
|
+
# This file is the source Rails uses to define your schema when running `rails
|
76
|
+
# db:schema:load`. When creating a new database, `rails db:schema:load` tends to
|
77
|
+
# be faster and is potentially less error prone than running all of your
|
78
|
+
# migrations from scratch. Old migrations may fail to apply correctly if those
|
79
|
+
# migrations use external dependencies or application code.
|
73
80
|
#
|
74
81
|
# It's strongly recommended that you check this file into your version control system.
|
75
82
|
|
@@ -104,6 +111,8 @@ HEADER
|
|
104
111
|
def table(table, stream)
|
105
112
|
columns = @connection.columns(table)
|
106
113
|
begin
|
114
|
+
self.table_name = table
|
115
|
+
|
107
116
|
tbl = StringIO.new
|
108
117
|
|
109
118
|
# first dump primary key column
|
@@ -137,7 +146,11 @@ HEADER
|
|
137
146
|
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
|
138
147
|
next if column.name == pk
|
139
148
|
type, colspec = column_spec(column)
|
140
|
-
|
149
|
+
if type.is_a?(Symbol)
|
150
|
+
tbl.print " t.#{type} #{column.name.inspect}"
|
151
|
+
else
|
152
|
+
tbl.print " t.column #{column.name.inspect}, #{type.inspect}"
|
153
|
+
end
|
141
154
|
tbl.print ", #{format_colspec(colspec)}" if colspec.present?
|
142
155
|
tbl.puts
|
143
156
|
end
|
@@ -153,6 +166,8 @@ HEADER
|
|
153
166
|
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
154
167
|
stream.puts "# #{e.message}"
|
155
168
|
stream.puts
|
169
|
+
ensure
|
170
|
+
self.table_name = nil
|
156
171
|
end
|
157
172
|
end
|
158
173
|
|
@@ -210,7 +225,7 @@ HEADER
|
|
210
225
|
parts << "primary_key: #{foreign_key.primary_key.inspect}"
|
211
226
|
end
|
212
227
|
|
213
|
-
if foreign_key.
|
228
|
+
if foreign_key.export_name_on_schema_dump?
|
214
229
|
parts << "name: #{foreign_key.name.inspect}"
|
215
230
|
end
|
216
231
|
|
@@ -10,12 +10,16 @@ module ActiveRecord
|
|
10
10
|
# to be executed the next time.
|
11
11
|
class SchemaMigration < ActiveRecord::Base # :nodoc:
|
12
12
|
class << self
|
13
|
+
def _internal?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
13
17
|
def primary_key
|
14
18
|
"version"
|
15
19
|
end
|
16
20
|
|
17
21
|
def table_name
|
18
|
-
"#{table_name_prefix}#{
|
22
|
+
"#{table_name_prefix}#{schema_migrations_table_name}#{table_name_suffix}"
|
19
23
|
end
|
20
24
|
|
21
25
|
def table_exists?
|
@@ -100,7 +100,7 @@ module ActiveRecord
|
|
100
100
|
self.default_scopes += [scope]
|
101
101
|
end
|
102
102
|
|
103
|
-
def build_default_scope(
|
103
|
+
def build_default_scope(relation = relation())
|
104
104
|
return if abstract_class?
|
105
105
|
|
106
106
|
if default_scope_override.nil?
|
@@ -111,15 +111,14 @@ module ActiveRecord
|
|
111
111
|
# The user has defined their own default scope method, so call that
|
112
112
|
evaluate_default_scope do
|
113
113
|
if scope = default_scope
|
114
|
-
|
114
|
+
relation.merge!(scope)
|
115
115
|
end
|
116
116
|
end
|
117
117
|
elsif default_scopes.any?
|
118
|
-
base_rel ||= relation
|
119
118
|
evaluate_default_scope do
|
120
|
-
default_scopes.inject(
|
119
|
+
default_scopes.inject(relation) do |default_scope, scope|
|
121
120
|
scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
|
122
|
-
default_scope.
|
121
|
+
default_scope.instance_exec(&scope) || default_scope
|
123
122
|
end
|
124
123
|
end
|
125
124
|
end
|
@@ -24,13 +24,21 @@ module ActiveRecord
|
|
24
24
|
# You can define a scope that applies to all finders using
|
25
25
|
# {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope].
|
26
26
|
def all
|
27
|
-
|
27
|
+
scope = current_scope
|
28
|
+
|
29
|
+
if scope
|
30
|
+
if scope._deprecated_scope_source
|
31
|
+
ActiveSupport::Deprecation.warn(<<~MSG.squish)
|
32
|
+
Class level methods will no longer inherit scoping from `#{scope._deprecated_scope_source}`
|
33
|
+
in Rails 6.1. To continue using the scoped relation, pass it into the block directly.
|
34
|
+
To instead access the full set of models, as Rails 6.1 will, use `#{name}.unscoped`.
|
35
|
+
MSG
|
36
|
+
end
|
28
37
|
|
29
|
-
|
30
|
-
|
31
|
-
current_scope.clone
|
38
|
+
if self == scope.klass
|
39
|
+
scope.clone
|
32
40
|
else
|
33
|
-
relation.merge!(
|
41
|
+
relation.merge!(scope)
|
34
42
|
end
|
35
43
|
else
|
36
44
|
default_scoped
|
@@ -38,9 +46,7 @@ module ActiveRecord
|
|
38
46
|
end
|
39
47
|
|
40
48
|
def scope_for_association(scope = relation) # :nodoc:
|
41
|
-
|
42
|
-
|
43
|
-
if current_scope && current_scope.empty_scope?
|
49
|
+
if current_scope&.empty_scope?
|
44
50
|
scope
|
45
51
|
else
|
46
52
|
default_scoped(scope)
|
@@ -52,7 +58,7 @@ module ActiveRecord
|
|
52
58
|
end
|
53
59
|
|
54
60
|
def default_extensions # :nodoc:
|
55
|
-
if scope =
|
61
|
+
if scope = scope_for_association || build_default_scope
|
56
62
|
scope.extensions
|
57
63
|
else
|
58
64
|
[]
|
@@ -181,16 +187,14 @@ module ActiveRecord
|
|
181
187
|
extension = Module.new(&block) if block
|
182
188
|
|
183
189
|
if body.respond_to?(:to_proc)
|
184
|
-
singleton_class.
|
185
|
-
scope = all
|
186
|
-
scope = scope._exec_scope(*args, &body)
|
190
|
+
singleton_class.define_method(name) do |*args|
|
191
|
+
scope = all._exec_scope(name, *args, &body)
|
187
192
|
scope = scope.extending(extension) if extension
|
188
193
|
scope
|
189
194
|
end
|
190
195
|
else
|
191
|
-
singleton_class.
|
192
|
-
scope = all
|
193
|
-
scope = scope.scoping { body.call(*args) || scope }
|
196
|
+
singleton_class.define_method(name) do |*args|
|
197
|
+
scope = body.call(*args) || all
|
194
198
|
scope = scope.extending(extension) if extension
|
195
199
|
scope
|
196
200
|
end
|
@@ -12,14 +12,6 @@ module ActiveRecord
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module ClassMethods # :nodoc:
|
15
|
-
def current_scope(skip_inherited_scope = false)
|
16
|
-
ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
|
17
|
-
end
|
18
|
-
|
19
|
-
def current_scope=(scope)
|
20
|
-
ScopeRegistry.set_value_for(:current_scope, self, scope)
|
21
|
-
end
|
22
|
-
|
23
15
|
# Collects attributes from scopes that should be applied when creating
|
24
16
|
# an AR instance for the particular class this is called on.
|
25
17
|
def scope_attributes
|
@@ -30,6 +22,14 @@ module ActiveRecord
|
|
30
22
|
def scope_attributes?
|
31
23
|
current_scope
|
32
24
|
end
|
25
|
+
|
26
|
+
def current_scope(skip_inherited_scope = false)
|
27
|
+
ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
|
28
|
+
end
|
29
|
+
|
30
|
+
def current_scope=(scope)
|
31
|
+
ScopeRegistry.set_value_for(:current_scope, self, scope)
|
32
|
+
end
|
33
33
|
end
|
34
34
|
|
35
35
|
def populate_with_current_scope_attributes # :nodoc:
|
@@ -44,7 +44,7 @@ module ActiveRecord
|
|
44
44
|
def initialize(values)
|
45
45
|
@values = values
|
46
46
|
@indexes = values.each_with_index.find_all { |thing, i|
|
47
|
-
|
47
|
+
Substitute === thing
|
48
48
|
}.map(&:last)
|
49
49
|
end
|
50
50
|
|
@@ -56,6 +56,28 @@ module ActiveRecord
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
class PartialQueryCollector
|
60
|
+
def initialize
|
61
|
+
@parts = []
|
62
|
+
@binds = []
|
63
|
+
end
|
64
|
+
|
65
|
+
def <<(str)
|
66
|
+
@parts << str
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_bind(obj)
|
71
|
+
@binds << obj
|
72
|
+
@parts << Substitute.new
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def value
|
77
|
+
[@parts, @binds]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
59
81
|
def self.query(sql)
|
60
82
|
Query.new(sql)
|
61
83
|
end
|
@@ -64,6 +86,10 @@ module ActiveRecord
|
|
64
86
|
PartialQuery.new(values)
|
65
87
|
end
|
66
88
|
|
89
|
+
def self.partial_query_collector
|
90
|
+
PartialQueryCollector.new
|
91
|
+
end
|
92
|
+
|
67
93
|
class Params # :nodoc:
|
68
94
|
def bind; Substitute.new; end
|
69
95
|
end
|
@@ -106,6 +132,8 @@ module ActiveRecord
|
|
106
132
|
sql = query_builder.sql_for bind_values, connection
|
107
133
|
|
108
134
|
klass.find_by_sql(sql, bind_values, preparable: true, &block)
|
135
|
+
rescue ::RangeError
|
136
|
+
nil
|
109
137
|
end
|
110
138
|
|
111
139
|
def self.unsupported_value?(value)
|
@@ -114,8 +142,7 @@ module ActiveRecord
|
|
114
142
|
end
|
115
143
|
end
|
116
144
|
|
117
|
-
|
118
|
-
|
145
|
+
private
|
119
146
|
attr_reader :query_builder, :bind_map, :klass
|
120
147
|
end
|
121
148
|
end
|
data/lib/active_record/store.rb
CHANGED
@@ -11,14 +11,20 @@ module ActiveRecord
|
|
11
11
|
# of the model. This is very helpful for easily exposing store keys to a form or elsewhere that's
|
12
12
|
# already built around just accessing attributes on the model.
|
13
13
|
#
|
14
|
+
# Every accessor comes with dirty tracking methods (+key_changed?+, +key_was+ and +key_change+) and
|
15
|
+
# methods to access the changes made during the last save (+saved_change_to_key?+, +saved_change_to_key+ and
|
16
|
+
# +key_before_last_save+).
|
17
|
+
#
|
18
|
+
# NOTE: There is no +key_will_change!+ method for accessors, use +store_will_change!+ instead.
|
19
|
+
#
|
14
20
|
# Make sure that you declare the database column used for the serialized store as a text, so there's
|
15
21
|
# plenty of room.
|
16
22
|
#
|
17
23
|
# You can set custom coder to encode/decode your serialized attributes to/from different formats.
|
18
24
|
# JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+.
|
19
25
|
#
|
20
|
-
# NOTE: If you are using
|
21
|
-
# the serialization provided by {.store}[rdoc-ref:rdoc-ref:ClassMethods#store].
|
26
|
+
# NOTE: If you are using structured database data types (eg. PostgreSQL +hstore+/+json+, or MySQL 5.7+
|
27
|
+
# +json+) there is no need for the serialization provided by {.store}[rdoc-ref:rdoc-ref:ClassMethods#store].
|
22
28
|
# Simply use {.store_accessor}[rdoc-ref:ClassMethods#store_accessor] instead to generate
|
23
29
|
# the accessor methods. Be aware that these columns use a string keyed hash and do not allow access
|
24
30
|
# using a symbol.
|
@@ -31,24 +37,40 @@ module ActiveRecord
|
|
31
37
|
#
|
32
38
|
# class User < ActiveRecord::Base
|
33
39
|
# store :settings, accessors: [ :color, :homepage ], coder: JSON
|
40
|
+
# store :parent, accessors: [ :name ], coder: JSON, prefix: true
|
41
|
+
# store :spouse, accessors: [ :name ], coder: JSON, prefix: :partner
|
42
|
+
# store :settings, accessors: [ :two_factor_auth ], suffix: true
|
43
|
+
# store :settings, accessors: [ :login_retry ], suffix: :config
|
34
44
|
# end
|
35
45
|
#
|
36
|
-
# u = User.new(color: 'black', homepage: '37signals.com')
|
46
|
+
# u = User.new(color: 'black', homepage: '37signals.com', parent_name: 'Mary', partner_name: 'Lily')
|
37
47
|
# u.color # Accessor stored attribute
|
48
|
+
# u.parent_name # Accessor stored attribute with prefix
|
49
|
+
# u.partner_name # Accessor stored attribute with custom prefix
|
50
|
+
# u.two_factor_auth_settings # Accessor stored attribute with suffix
|
51
|
+
# u.login_retry_config # Accessor stored attribute with custom suffix
|
38
52
|
# u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
|
39
53
|
#
|
40
54
|
# # There is no difference between strings and symbols for accessing custom attributes
|
41
55
|
# u.settings[:country] # => 'Denmark'
|
42
56
|
# u.settings['country'] # => 'Denmark'
|
43
57
|
#
|
58
|
+
# # Dirty tracking
|
59
|
+
# u.color = 'green'
|
60
|
+
# u.color_changed? # => true
|
61
|
+
# u.color_was # => 'black'
|
62
|
+
# u.color_change # => ['black', 'red']
|
63
|
+
#
|
44
64
|
# # Add additional accessors to an existing store through store_accessor
|
45
65
|
# class SuperUser < User
|
46
66
|
# store_accessor :settings, :privileges, :servants
|
67
|
+
# store_accessor :parent, :birthday, prefix: true
|
68
|
+
# store_accessor :settings, :secret_question, suffix: :config
|
47
69
|
# end
|
48
70
|
#
|
49
71
|
# The stored attribute names can be retrieved using {.stored_attributes}[rdoc-ref:rdoc-ref:ClassMethods#stored_attributes].
|
50
72
|
#
|
51
|
-
# User.stored_attributes[:settings] # [:color, :homepage]
|
73
|
+
# User.stored_attributes[:settings] # [:color, :homepage, :two_factor_auth, :login_retry]
|
52
74
|
#
|
53
75
|
# == Overwriting default accessors
|
54
76
|
#
|
@@ -81,21 +103,78 @@ module ActiveRecord
|
|
81
103
|
module ClassMethods
|
82
104
|
def store(store_attribute, options = {})
|
83
105
|
serialize store_attribute, IndifferentCoder.new(store_attribute, options[:coder])
|
84
|
-
store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
|
106
|
+
store_accessor(store_attribute, options[:accessors], options.slice(:prefix, :suffix)) if options.has_key? :accessors
|
85
107
|
end
|
86
108
|
|
87
|
-
def store_accessor(store_attribute, *keys)
|
109
|
+
def store_accessor(store_attribute, *keys, prefix: nil, suffix: nil)
|
88
110
|
keys = keys.flatten
|
89
111
|
|
112
|
+
accessor_prefix =
|
113
|
+
case prefix
|
114
|
+
when String, Symbol
|
115
|
+
"#{prefix}_"
|
116
|
+
when TrueClass
|
117
|
+
"#{store_attribute}_"
|
118
|
+
else
|
119
|
+
""
|
120
|
+
end
|
121
|
+
accessor_suffix =
|
122
|
+
case suffix
|
123
|
+
when String, Symbol
|
124
|
+
"_#{suffix}"
|
125
|
+
when TrueClass
|
126
|
+
"_#{store_attribute}"
|
127
|
+
else
|
128
|
+
""
|
129
|
+
end
|
130
|
+
|
90
131
|
_store_accessors_module.module_eval do
|
91
132
|
keys.each do |key|
|
92
|
-
|
133
|
+
accessor_key = "#{accessor_prefix}#{key}#{accessor_suffix}"
|
134
|
+
|
135
|
+
define_method("#{accessor_key}=") do |value|
|
93
136
|
write_store_attribute(store_attribute, key, value)
|
94
137
|
end
|
95
138
|
|
96
|
-
define_method(
|
139
|
+
define_method(accessor_key) do
|
97
140
|
read_store_attribute(store_attribute, key)
|
98
141
|
end
|
142
|
+
|
143
|
+
define_method("#{accessor_key}_changed?") do
|
144
|
+
return false unless attribute_changed?(store_attribute)
|
145
|
+
prev_store, new_store = changes[store_attribute]
|
146
|
+
prev_store&.dig(key) != new_store&.dig(key)
|
147
|
+
end
|
148
|
+
|
149
|
+
define_method("#{accessor_key}_change") do
|
150
|
+
return unless attribute_changed?(store_attribute)
|
151
|
+
prev_store, new_store = changes[store_attribute]
|
152
|
+
[prev_store&.dig(key), new_store&.dig(key)]
|
153
|
+
end
|
154
|
+
|
155
|
+
define_method("#{accessor_key}_was") do
|
156
|
+
return unless attribute_changed?(store_attribute)
|
157
|
+
prev_store, _new_store = changes[store_attribute]
|
158
|
+
prev_store&.dig(key)
|
159
|
+
end
|
160
|
+
|
161
|
+
define_method("saved_change_to_#{accessor_key}?") do
|
162
|
+
return false unless saved_change_to_attribute?(store_attribute)
|
163
|
+
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
164
|
+
prev_store&.dig(key) != new_store&.dig(key)
|
165
|
+
end
|
166
|
+
|
167
|
+
define_method("saved_change_to_#{accessor_key}") do
|
168
|
+
return unless saved_change_to_attribute?(store_attribute)
|
169
|
+
prev_store, new_store = saved_change_to_attribute(store_attribute)
|
170
|
+
[prev_store&.dig(key), new_store&.dig(key)]
|
171
|
+
end
|
172
|
+
|
173
|
+
define_method("#{accessor_key}_before_last_save") do
|
174
|
+
return unless saved_change_to_attribute?(store_attribute)
|
175
|
+
prev_store, _new_store = saved_change_to_attribute(store_attribute)
|
176
|
+
prev_store&.dig(key)
|
177
|
+
end
|
99
178
|
end
|
100
179
|
end
|
101
180
|
|
@@ -4,17 +4,18 @@ module ActiveRecord
|
|
4
4
|
class TableMetadata # :nodoc:
|
5
5
|
delegate :foreign_type, :foreign_key, :join_primary_key, :join_foreign_key, to: :association, prefix: true
|
6
6
|
|
7
|
-
def initialize(klass, arel_table, association = nil)
|
7
|
+
def initialize(klass, arel_table, association = nil, types = klass)
|
8
8
|
@klass = klass
|
9
|
+
@types = types
|
9
10
|
@arel_table = arel_table
|
10
11
|
@association = association
|
11
12
|
end
|
12
13
|
|
13
14
|
def resolve_column_aliases(hash)
|
14
15
|
new_hash = hash.dup
|
15
|
-
hash.
|
16
|
-
if
|
17
|
-
new_hash[
|
16
|
+
hash.each_key do |key|
|
17
|
+
if key.is_a?(Symbol) && new_key = klass.attribute_aliases[key.to_s]
|
18
|
+
new_hash[new_key] = new_hash.delete(key)
|
18
19
|
end
|
19
20
|
end
|
20
21
|
new_hash
|
@@ -29,11 +30,7 @@ module ActiveRecord
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def type(column_name)
|
32
|
-
|
33
|
-
klass.type_for_attribute(column_name)
|
34
|
-
else
|
35
|
-
Type.default_value
|
36
|
-
end
|
33
|
+
types.type_for_attribute(column_name)
|
37
34
|
end
|
38
35
|
|
39
36
|
def has_column?(column_name)
|
@@ -52,13 +49,12 @@ module ActiveRecord
|
|
52
49
|
elsif association && !association.polymorphic?
|
53
50
|
association_klass = association.klass
|
54
51
|
arel_table = association_klass.arel_table.alias(table_name)
|
52
|
+
TableMetadata.new(association_klass, arel_table, association)
|
55
53
|
else
|
56
54
|
type_caster = TypeCaster::Connection.new(klass, table_name)
|
57
|
-
association_klass = nil
|
58
55
|
arel_table = Arel::Table.new(table_name, type_caster: type_caster)
|
56
|
+
TableMetadata.new(nil, arel_table, association, type_caster)
|
59
57
|
end
|
60
|
-
|
61
|
-
TableMetadata.new(association_klass, arel_table, association)
|
62
58
|
end
|
63
59
|
|
64
60
|
def polymorphic_association?
|
@@ -73,10 +69,7 @@ module ActiveRecord
|
|
73
69
|
klass.reflect_on_aggregation(aggregation_name)
|
74
70
|
end
|
75
71
|
|
76
|
-
|
77
|
-
|
78
|
-
protected
|
79
|
-
|
80
|
-
attr_reader :klass, :arel_table, :association
|
72
|
+
private
|
73
|
+
attr_reader :klass, :types, :arel_table, :association
|
81
74
|
end
|
82
75
|
end
|