activerecord 4.2.11.3 → 5.0.0.beta1
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 +1029 -1349
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/examples/performance.rb +2 -2
- data/lib/active_record.rb +7 -3
- data/lib/active_record/aggregations.rb +35 -25
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations.rb +305 -204
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +10 -8
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +20 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +41 -18
- data/lib/active_record/associations/builder/collection_association.rb +8 -24
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +10 -5
- data/lib/active_record/associations/builder/singular_association.rb +2 -9
- data/lib/active_record/associations/collection_association.rb +40 -43
- data/lib/active_record/associations/collection_proxy.rb +55 -29
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +20 -71
- data/lib/active_record/associations/has_many_through_association.rb +8 -52
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +28 -18
- data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
- data/lib/active_record/associations/preloader.rb +13 -4
- data/lib/active_record/associations/preloader/association.rb +45 -51
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +5 -4
- data/lib/active_record/associations/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/attribute.rb +61 -17
- data/lib/active_record/attribute/user_provided_default.rb +23 -0
- data/lib/active_record/attribute_assignment.rb +27 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +79 -26
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +26 -42
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
- data/lib/active_record/attribute_methods/write.rb +13 -24
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attributes.rb +194 -81
- data/lib/active_record/autosave_association.rb +33 -15
- data/lib/active_record/base.rb +30 -18
- data/lib/active_record/callbacks.rb +36 -40
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +31 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
- data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
- data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
- data/lib/active_record/connection_adapters/column.rb +27 -41
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
- data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
- data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
- data/lib/active_record/connection_handling.rb +5 -5
- data/lib/active_record/core.rb +72 -104
- data/lib/active_record/counter_cache.rb +9 -20
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +110 -76
- data/lib/active_record/errors.rb +72 -47
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +19 -4
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +27 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +10 -14
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +40 -22
- data/lib/active_record/migration.rb +304 -133
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +90 -0
- data/lib/active_record/model_schema.rb +92 -40
- data/lib/active_record/nested_attributes.rb +45 -34
- data/lib/active_record/null_relation.rb +15 -7
- data/lib/active_record/persistence.rb +112 -72
- data/lib/active_record/querying.rb +6 -5
- data/lib/active_record/railtie.rb +20 -13
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +47 -38
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +182 -57
- data/lib/active_record/relation.rb +152 -100
- data/lib/active_record/relation/batches.rb +133 -33
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +80 -101
- data/lib/active_record/relation/delegation.rb +6 -19
- data/lib/active_record/relation/finder_methods.rb +58 -46
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +13 -42
- data/lib/active_record/relation/predicate_builder.rb +99 -105
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +274 -238
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +3 -6
- data/lib/active_record/relation/where_clause.rb +173 -0
- data/lib/active_record/relation/where_clause_factory.rb +37 -0
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +94 -65
- data/lib/active_record/schema.rb +23 -22
- data/lib/active_record/schema_dumper.rb +33 -22
- data/lib/active_record/schema_migration.rb +10 -4
- data/lib/active_record/scoping.rb +17 -6
- data/lib/active_record/scoping/default.rb +19 -6
- data/lib/active_record/scoping/named.rb +39 -28
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +15 -13
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +54 -0
- data/lib/active_record/table_metadata.rb +64 -0
- data/lib/active_record/tasks/database_tasks.rb +30 -40
- data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +16 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +138 -56
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +33 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +9 -14
- data/lib/active_record/type/time.rb +3 -21
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +24 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +36 -0
- data/lib/active_record/validations/presence.rb +12 -12
- data/lib/active_record/validations/uniqueness.rb +24 -21
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +50 -35
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- 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/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- 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/decimal_without_scale.rb +0 -11
- 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/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -5,15 +5,36 @@ module ActiveRecord
|
|
5
5
|
# knows how to invert the following commands:
|
6
6
|
#
|
7
7
|
# * add_column
|
8
|
+
# * add_foreign_key
|
8
9
|
# * add_index
|
10
|
+
# * add_reference
|
9
11
|
# * add_timestamps
|
10
|
-
# *
|
12
|
+
# * change_column
|
13
|
+
# * change_column_default (must supply a :from and :to option)
|
14
|
+
# * change_column_null
|
11
15
|
# * create_join_table
|
16
|
+
# * create_table
|
17
|
+
# * disable_extension
|
18
|
+
# * drop_join_table
|
19
|
+
# * drop_table (must supply a block)
|
20
|
+
# * enable_extension
|
21
|
+
# * remove_column (must supply a type)
|
22
|
+
# * remove_columns (must specify at least one column name or more)
|
23
|
+
# * remove_foreign_key (must supply a second table)
|
24
|
+
# * remove_index
|
25
|
+
# * remove_reference
|
12
26
|
# * remove_timestamps
|
13
27
|
# * rename_column
|
14
28
|
# * rename_index
|
15
29
|
# * rename_table
|
16
30
|
class CommandRecorder
|
31
|
+
ReversibleAndIrreversibleMethods = [:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
|
32
|
+
:rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
|
33
|
+
:change_column_default, :add_reference, :remove_reference, :transaction,
|
34
|
+
:drop_join_table, :drop_table, :execute_block, :enable_extension, :disable_extension,
|
35
|
+
:change_column, :execute, :remove_columns, :change_column_null,
|
36
|
+
:add_foreign_key, :remove_foreign_key
|
37
|
+
]
|
17
38
|
include JoinTable
|
18
39
|
|
19
40
|
attr_accessor :commands, :delegate, :reverting
|
@@ -41,7 +62,7 @@ module ActiveRecord
|
|
41
62
|
@reverting = !@reverting
|
42
63
|
end
|
43
64
|
|
44
|
-
#
|
65
|
+
# Record +command+. +command+ should be a method name and arguments.
|
45
66
|
# For example:
|
46
67
|
#
|
47
68
|
# recorder.record(:method_name, [:arg1, :arg2])
|
@@ -62,7 +83,12 @@ module ActiveRecord
|
|
62
83
|
# invert the +command+.
|
63
84
|
def inverse_of(command, args, &block)
|
64
85
|
method = :"invert_#{command}"
|
65
|
-
raise IrreversibleMigration unless respond_to?(method, true)
|
86
|
+
raise IrreversibleMigration, <<-MSG.strip_heredoc unless respond_to?(method, true)
|
87
|
+
This migration uses #{command}, which is not automatically reversible.
|
88
|
+
To make the migration reversible you can either:
|
89
|
+
1. Define #up and #down methods in place of the #change method.
|
90
|
+
2. Use the #reversible method to define reversible behavior.
|
91
|
+
MSG
|
66
92
|
send(method, args, &block)
|
67
93
|
end
|
68
94
|
|
@@ -70,14 +96,7 @@ module ActiveRecord
|
|
70
96
|
super || delegate.respond_to?(*args)
|
71
97
|
end
|
72
98
|
|
73
|
-
|
74
|
-
:rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
|
75
|
-
:change_column_default, :add_reference, :remove_reference, :transaction,
|
76
|
-
:drop_join_table, :drop_table, :execute_block, :enable_extension,
|
77
|
-
:change_column, :execute, :remove_columns, :change_column_null,
|
78
|
-
:add_foreign_key, :remove_foreign_key
|
79
|
-
# irreversible methods need to be here too
|
80
|
-
].each do |method|
|
99
|
+
ReversibleAndIrreversibleMethods.each do |method|
|
81
100
|
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
82
101
|
def #{method}(*args, &block) # def create_table(*args, &block)
|
83
102
|
record(:"#{method}", args, &block) # record(:create_table, args, &block)
|
@@ -151,19 +170,31 @@ module ActiveRecord
|
|
151
170
|
end
|
152
171
|
|
153
172
|
def invert_remove_index(args)
|
154
|
-
table,
|
155
|
-
|
156
|
-
|
157
|
-
|
173
|
+
table, options_or_column = *args
|
174
|
+
if (options = options_or_column).is_a?(Hash)
|
175
|
+
unless options[:column]
|
176
|
+
raise ActiveRecord::IrreversibleMigration, "remove_index is only reversible if given a :column option."
|
177
|
+
end
|
178
|
+
options = options.dup
|
179
|
+
[:add_index, [table, options.delete(:column), options]]
|
180
|
+
elsif (column = options_or_column).present?
|
181
|
+
[:add_index, [table, column]]
|
158
182
|
end
|
159
|
-
|
160
|
-
options = options.dup
|
161
|
-
[:add_index, [table, options.delete(:column), options]]
|
162
183
|
end
|
163
184
|
|
164
185
|
alias :invert_add_belongs_to :invert_add_reference
|
165
186
|
alias :invert_remove_belongs_to :invert_remove_reference
|
166
187
|
|
188
|
+
def invert_change_column_default(args)
|
189
|
+
table, column, options = *args
|
190
|
+
|
191
|
+
unless options && options.is_a?(Hash) && options.has_key?(:from) && options.has_key?(:to)
|
192
|
+
raise ActiveRecord::IrreversibleMigration, "change_column_default is only reversible if given a :from and :to option."
|
193
|
+
end
|
194
|
+
|
195
|
+
[:change_column_default, [table, column, from: options[:to], to: options[:from]]]
|
196
|
+
end
|
197
|
+
|
167
198
|
def invert_change_column_null(args)
|
168
199
|
args[2] = !args[2]
|
169
200
|
[:change_column_null, args]
|
@@ -184,6 +215,16 @@ module ActiveRecord
|
|
184
215
|
[:remove_foreign_key, [from_table, options]]
|
185
216
|
end
|
186
217
|
|
218
|
+
def invert_remove_foreign_key(args)
|
219
|
+
from_table, to_table, remove_options = args
|
220
|
+
raise ActiveRecord::IrreversibleMigration, "remove_foreign_key is only reversible if given a second table" if to_table.nil? || to_table.is_a?(Hash)
|
221
|
+
|
222
|
+
reversed_args = [from_table, to_table]
|
223
|
+
reversed_args << remove_options if remove_options
|
224
|
+
|
225
|
+
[:add_foreign_key, reversed_args]
|
226
|
+
end
|
227
|
+
|
187
228
|
# Forwards any missing method call to the \target.
|
188
229
|
def method_missing(method, *args, &block)
|
189
230
|
if @delegate.respond_to?(method)
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Migration
|
3
|
+
module Compatibility # :nodoc: all
|
4
|
+
V5_0 = Current
|
5
|
+
|
6
|
+
module FourTwoShared
|
7
|
+
module TableDefinition
|
8
|
+
def timestamps(*, **options)
|
9
|
+
options[:null] = true if options[:null].nil?
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_table(table_name, options = {})
|
15
|
+
if block_given?
|
16
|
+
super(table_name, options) do |t|
|
17
|
+
class << t
|
18
|
+
prepend TableDefinition
|
19
|
+
end
|
20
|
+
yield t
|
21
|
+
end
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_timestamps(*, **options)
|
28
|
+
options[:null] = true if options[:null].nil?
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def index_exists?(table_name, column_name, options = {})
|
33
|
+
column_names = Array(column_name).map(&:to_s)
|
34
|
+
options[:name] =
|
35
|
+
if options.key?(:name).present?
|
36
|
+
options[:name].to_s
|
37
|
+
else
|
38
|
+
index_name(table_name, column: column_names)
|
39
|
+
end
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
def remove_index(table_name, options = {})
|
44
|
+
index_name = index_name_for_remove(table_name, options)
|
45
|
+
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def index_name_for_remove(table_name, options = {})
|
51
|
+
index_name = index_name(table_name, options)
|
52
|
+
|
53
|
+
unless index_name_exists?(table_name, index_name, true)
|
54
|
+
if options.is_a?(Hash) && options.has_key?(:name)
|
55
|
+
options_without_column = options.dup
|
56
|
+
options_without_column.delete :column
|
57
|
+
index_name_without_column = index_name(table_name, options_without_column)
|
58
|
+
|
59
|
+
return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
|
60
|
+
end
|
61
|
+
|
62
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
|
63
|
+
end
|
64
|
+
|
65
|
+
index_name
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class V4_2 < V5_0
|
70
|
+
# 4.2 is defined as a module because it needs to be shared with
|
71
|
+
# Legacy. When the time comes, V5_0 should be defined straight
|
72
|
+
# in its class.
|
73
|
+
include FourTwoShared
|
74
|
+
end
|
75
|
+
|
76
|
+
module Legacy
|
77
|
+
include FourTwoShared
|
78
|
+
|
79
|
+
def run(*)
|
80
|
+
ActiveSupport::Deprecation.warn \
|
81
|
+
"Directly inheriting from ActiveRecord::Migration is deprecated. " \
|
82
|
+
"Please specify the Rails release the migration was written for:\n" \
|
83
|
+
"\n" \
|
84
|
+
" class #{self.class.name} < ActiveRecord::Migration[4.2]"
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -50,6 +50,13 @@ module ActiveRecord
|
|
50
50
|
class_attribute :pluralize_table_names, instance_writer: false
|
51
51
|
self.pluralize_table_names = true
|
52
52
|
|
53
|
+
##
|
54
|
+
# :singleton-method:
|
55
|
+
# Accessor for the list of columns names the model should ignore. Ignored columns won't have attribute
|
56
|
+
# accessors defined, and won't be referenced in SQL queries.
|
57
|
+
class_attribute :ignored_columns, instance_accessor: false
|
58
|
+
self.ignored_columns = [].freeze
|
59
|
+
|
53
60
|
self.inheritance_column = 'type'
|
54
61
|
|
55
62
|
delegate :type_for_attribute, to: :class
|
@@ -111,17 +118,6 @@ module ActiveRecord
|
|
111
118
|
# class Mouse < ActiveRecord::Base
|
112
119
|
# self.table_name = "mice"
|
113
120
|
# end
|
114
|
-
#
|
115
|
-
# Alternatively, you can override the table_name method to define your
|
116
|
-
# own computation. (Possibly using <tt>super</tt> to manipulate the default
|
117
|
-
# table name.) Example:
|
118
|
-
#
|
119
|
-
# class Post < ActiveRecord::Base
|
120
|
-
# def self.table_name
|
121
|
-
# "special_" + super
|
122
|
-
# end
|
123
|
-
# end
|
124
|
-
# Post.table_name # => "special_posts"
|
125
121
|
def table_name
|
126
122
|
reset_table_name unless defined?(@table_name)
|
127
123
|
@table_name
|
@@ -132,9 +128,6 @@ module ActiveRecord
|
|
132
128
|
# class Project < ActiveRecord::Base
|
133
129
|
# self.table_name = "project"
|
134
130
|
# end
|
135
|
-
#
|
136
|
-
# You can also just define your own <tt>self.table_name</tt> method; see
|
137
|
-
# the documentation for ActiveRecord::Base#table_name.
|
138
131
|
def table_name=(value)
|
139
132
|
value = value && value.to_s
|
140
133
|
|
@@ -147,7 +140,7 @@ module ActiveRecord
|
|
147
140
|
@quoted_table_name = nil
|
148
141
|
@arel_table = nil
|
149
142
|
@sequence_name = nil unless defined?(@explicit_sequence_name) && @explicit_sequence_name
|
150
|
-
@
|
143
|
+
@predicate_builder = nil
|
151
144
|
end
|
152
145
|
|
153
146
|
# Returns a quoted version of the table name, used to construct SQL statements.
|
@@ -227,37 +220,46 @@ module ActiveRecord
|
|
227
220
|
|
228
221
|
# Indicates whether the table associated with this class exists
|
229
222
|
def table_exists?
|
230
|
-
connection.schema_cache.
|
223
|
+
connection.schema_cache.data_source_exists?(table_name)
|
231
224
|
end
|
232
225
|
|
233
226
|
def attributes_builder # :nodoc:
|
234
|
-
@attributes_builder ||= AttributeSet::Builder.new(
|
227
|
+
@attributes_builder ||= AttributeSet::Builder.new(attribute_types, primary_key)
|
235
228
|
end
|
236
229
|
|
237
|
-
def
|
238
|
-
|
239
|
-
|
240
|
-
|
230
|
+
def columns_hash # :nodoc:
|
231
|
+
load_schema
|
232
|
+
@columns_hash
|
233
|
+
end
|
234
|
+
|
235
|
+
def columns
|
236
|
+
load_schema
|
237
|
+
@columns ||= columns_hash.values
|
238
|
+
end
|
239
|
+
|
240
|
+
def attribute_types # :nodoc:
|
241
|
+
load_schema
|
242
|
+
@attribute_types ||= Hash.new(Type::Value.new)
|
241
243
|
end
|
242
244
|
|
243
245
|
def type_for_attribute(attr_name) # :nodoc:
|
244
|
-
|
246
|
+
attribute_types[attr_name]
|
245
247
|
end
|
246
248
|
|
247
249
|
# Returns a hash where the keys are column names and the values are
|
248
|
-
# default values when instantiating the
|
250
|
+
# default values when instantiating the Active Record object for this table.
|
249
251
|
def column_defaults
|
250
|
-
|
252
|
+
load_schema
|
253
|
+
_default_attributes.to_hash
|
251
254
|
end
|
252
255
|
|
253
256
|
def _default_attributes # :nodoc:
|
254
|
-
@default_attributes ||=
|
255
|
-
raw_default_values)
|
257
|
+
@default_attributes ||= AttributeSet.new({})
|
256
258
|
end
|
257
259
|
|
258
260
|
# Returns an array of column names as strings.
|
259
261
|
def column_names
|
260
|
-
@column_names ||= columns.map
|
262
|
+
@column_names ||= columns.map(&:name)
|
261
263
|
end
|
262
264
|
|
263
265
|
# Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
|
@@ -273,7 +275,7 @@ module ActiveRecord
|
|
273
275
|
# when just after creating a table you want to populate it with some default
|
274
276
|
# values, eg:
|
275
277
|
#
|
276
|
-
# class CreateJobLevels < ActiveRecord::Migration
|
278
|
+
# class CreateJobLevels < ActiveRecord::Migration[5.0]
|
277
279
|
# def up
|
278
280
|
# create_table :job_levels do |t|
|
279
281
|
# t.integer :id
|
@@ -295,21 +297,53 @@ module ActiveRecord
|
|
295
297
|
def reset_column_information
|
296
298
|
connection.clear_cache!
|
297
299
|
undefine_attribute_methods
|
298
|
-
connection.schema_cache.
|
300
|
+
connection.schema_cache.clear_data_source_cache!(table_name)
|
299
301
|
|
300
|
-
|
301
|
-
@column_names = nil
|
302
|
-
@column_types = nil
|
303
|
-
@content_columns = nil
|
304
|
-
@default_attributes = nil
|
305
|
-
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
|
306
|
-
@relation = nil
|
307
|
-
|
308
|
-
initialize_find_by_cache
|
302
|
+
reload_schema_from_cache
|
309
303
|
end
|
310
304
|
|
311
305
|
private
|
312
306
|
|
307
|
+
def schema_loaded?
|
308
|
+
defined?(@columns_hash) && @columns_hash
|
309
|
+
end
|
310
|
+
|
311
|
+
def load_schema
|
312
|
+
unless schema_loaded?
|
313
|
+
load_schema!
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def load_schema!
|
318
|
+
@columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
|
319
|
+
@columns_hash.each do |name, column|
|
320
|
+
warn_if_deprecated_type(column)
|
321
|
+
define_attribute(
|
322
|
+
name,
|
323
|
+
connection.lookup_cast_type_from_column(column),
|
324
|
+
default: column.default,
|
325
|
+
user_provided_default: false
|
326
|
+
)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def reload_schema_from_cache
|
331
|
+
@arel_engine = nil
|
332
|
+
@arel_table = nil
|
333
|
+
@column_names = nil
|
334
|
+
@attribute_types = nil
|
335
|
+
@content_columns = nil
|
336
|
+
@default_attributes = nil
|
337
|
+
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
|
338
|
+
@attributes_builder = nil
|
339
|
+
@columns = nil
|
340
|
+
@columns_hash = nil
|
341
|
+
@attribute_names = nil
|
342
|
+
direct_descendants.each do |descendant|
|
343
|
+
descendant.send(:reload_schema_from_cache)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
313
347
|
# Guesses the table name, but does not decorate it with prefix and suffix information.
|
314
348
|
def undecorated_table_name(class_name = base_class.name)
|
315
349
|
table_name = class_name.to_s.demodulize.underscore
|
@@ -334,8 +368,26 @@ module ActiveRecord
|
|
334
368
|
end
|
335
369
|
end
|
336
370
|
|
337
|
-
def
|
338
|
-
|
371
|
+
def warn_if_deprecated_type(column)
|
372
|
+
return if attributes_to_define_after_schema_loads.key?(column.name)
|
373
|
+
if column.respond_to?(:oid) && column.sql_type.start_with?("point")
|
374
|
+
if column.array?
|
375
|
+
array_arguments = ", array: true"
|
376
|
+
else
|
377
|
+
array_arguments = ""
|
378
|
+
end
|
379
|
+
ActiveSupport::Deprecation.warn(<<-WARNING.strip_heredoc)
|
380
|
+
The behavior of the `:point` type will be changing in Rails 5.1 to
|
381
|
+
return a `Point` object, rather than an `Array`. If you'd like to
|
382
|
+
keep the old behavior, you can add this line to #{self.name}:
|
383
|
+
|
384
|
+
attribute :#{column.name}, :legacy_point#{array_arguments}
|
385
|
+
|
386
|
+
If you'd like the new behavior today, you can add this line:
|
387
|
+
|
388
|
+
attribute :#{column.name}, :point#{array_arguments}
|
389
|
+
WARNING
|
390
|
+
end
|
339
391
|
end
|
340
392
|
end
|
341
393
|
end
|
@@ -81,6 +81,9 @@ module ActiveRecord
|
|
81
81
|
#
|
82
82
|
# Note that the model will _not_ be destroyed until the parent is saved.
|
83
83
|
#
|
84
|
+
# Also note that the model will not be destroyed unless you also specify
|
85
|
+
# its id in the updated hash.
|
86
|
+
#
|
84
87
|
# === One-to-many
|
85
88
|
#
|
86
89
|
# Consider a member that has a number of posts:
|
@@ -111,7 +114,7 @@ module ActiveRecord
|
|
111
114
|
# member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
|
112
115
|
# member.posts.second.title # => 'The egalitarian assumption of the modern citizen'
|
113
116
|
#
|
114
|
-
# You may also set a
|
117
|
+
# You may also set a +:reject_if+ proc to silently ignore any new record
|
115
118
|
# hashes if they fail to pass your criteria. For example, the previous
|
116
119
|
# example could be rewritten as:
|
117
120
|
#
|
@@ -133,7 +136,7 @@ module ActiveRecord
|
|
133
136
|
# member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
|
134
137
|
# member.posts.second.title # => 'The egalitarian assumption of the modern citizen'
|
135
138
|
#
|
136
|
-
# Alternatively,
|
139
|
+
# Alternatively, +:reject_if+ also accepts a symbol for using methods:
|
137
140
|
#
|
138
141
|
# class Member < ActiveRecord::Base
|
139
142
|
# has_many :posts
|
@@ -144,8 +147,8 @@ module ActiveRecord
|
|
144
147
|
# has_many :posts
|
145
148
|
# accepts_nested_attributes_for :posts, reject_if: :reject_posts
|
146
149
|
#
|
147
|
-
# def reject_posts(
|
148
|
-
#
|
150
|
+
# def reject_posts(attributes)
|
151
|
+
# attributes['title'].blank?
|
149
152
|
# end
|
150
153
|
# end
|
151
154
|
#
|
@@ -163,6 +166,11 @@ module ActiveRecord
|
|
163
166
|
# member.posts.first.title # => '[UPDATED] An, as of yet, undisclosed awesome Ruby documentation browser!'
|
164
167
|
# member.posts.second.title # => '[UPDATED] other post'
|
165
168
|
#
|
169
|
+
# However, the above applies if the parent model is being updated as well.
|
170
|
+
# For example, If you wanted to create a +member+ named _joe_ and wanted to
|
171
|
+
# update the +posts+ at the same time, that would give an
|
172
|
+
# ActiveRecord::RecordNotFound error.
|
173
|
+
#
|
166
174
|
# By default the associated records are protected from being destroyed. If
|
167
175
|
# you want to destroy any of the associated records through the attributes
|
168
176
|
# hash, you have to enable it first using the <tt>:allow_destroy</tt>
|
@@ -205,20 +213,20 @@ module ActiveRecord
|
|
205
213
|
#
|
206
214
|
# Passing attributes for an associated collection in the form of a hash
|
207
215
|
# of hashes can be used with hashes generated from HTTP/HTML parameters,
|
208
|
-
# where there
|
216
|
+
# where there may be no natural way to submit an array of hashes.
|
209
217
|
#
|
210
218
|
# === Saving
|
211
219
|
#
|
212
220
|
# All changes to models, including the destruction of those marked for
|
213
221
|
# destruction, are saved and destroyed automatically and atomically when
|
214
222
|
# the parent model is saved. This happens inside the transaction initiated
|
215
|
-
# by the
|
223
|
+
# by the parent's save method. See ActiveRecord::AutosaveAssociation.
|
216
224
|
#
|
217
225
|
# === Validating the presence of a parent model
|
218
226
|
#
|
219
227
|
# If you want to validate that a child record is associated with a parent
|
220
|
-
# record, you can use
|
221
|
-
#
|
228
|
+
# record, you can use the +validates_presence_of+ method and the +:inverse_of+
|
229
|
+
# key as this example illustrates:
|
222
230
|
#
|
223
231
|
# class Member < ActiveRecord::Base
|
224
232
|
# has_many :posts, inverse_of: :member
|
@@ -230,7 +238,7 @@ module ActiveRecord
|
|
230
238
|
# validates_presence_of :member
|
231
239
|
# end
|
232
240
|
#
|
233
|
-
# Note that if you do not specify the
|
241
|
+
# Note that if you do not specify the +:inverse_of+ option, then
|
234
242
|
# Active Record will try to automatically guess the inverse association
|
235
243
|
# based on heuristics.
|
236
244
|
#
|
@@ -264,29 +272,31 @@ module ActiveRecord
|
|
264
272
|
# Allows you to specify a Proc or a Symbol pointing to a method
|
265
273
|
# that checks whether a record should be built for a certain attribute
|
266
274
|
# hash. The hash is passed to the supplied Proc or the method
|
267
|
-
# and it should return either +true+ or +false+. When no
|
275
|
+
# and it should return either +true+ or +false+. When no +:reject_if+
|
268
276
|
# is specified, a record will be built for all attribute hashes that
|
269
277
|
# do not have a <tt>_destroy</tt> value that evaluates to true.
|
270
278
|
# Passing <tt>:all_blank</tt> instead of a Proc will create a proc
|
271
279
|
# that will reject a record where all the attributes are blank excluding
|
272
|
-
# any value for _destroy
|
280
|
+
# any value for +_destroy+.
|
273
281
|
# [:limit]
|
274
|
-
# Allows you to specify the maximum number of
|
275
|
-
# can be processed with the nested attributes. Limit also can be specified
|
276
|
-
# Proc or a Symbol pointing to a method that should return number.
|
277
|
-
# nested attributes array exceeds the specified limit,
|
278
|
-
# exception is raised. If omitted, any
|
279
|
-
#
|
282
|
+
# Allows you to specify the maximum number of associated records that
|
283
|
+
# can be processed with the nested attributes. Limit also can be specified
|
284
|
+
# as a Proc or a Symbol pointing to a method that should return a number.
|
285
|
+
# If the size of the nested attributes array exceeds the specified limit,
|
286
|
+
# NestedAttributes::TooManyRecords exception is raised. If omitted, any
|
287
|
+
# number of associations can be processed.
|
288
|
+
# Note that the +:limit+ option is only applicable to one-to-many
|
289
|
+
# associations.
|
280
290
|
# [:update_only]
|
281
291
|
# For a one-to-one association, this option allows you to specify how
|
282
|
-
# nested attributes are to be used when an associated record already
|
292
|
+
# nested attributes are going to be used when an associated record already
|
283
293
|
# exists. In general, an existing record may either be updated with the
|
284
294
|
# new set of attribute values or be replaced by a wholly new record
|
285
|
-
# containing those values. By default the
|
295
|
+
# containing those values. By default the +:update_only+ option is +false+
|
286
296
|
# and the nested attributes are used to update the existing record only
|
287
297
|
# if they include the record's <tt>:id</tt> value. Otherwise a new
|
288
298
|
# record will be instantiated and used to replace the existing one.
|
289
|
-
# However if the
|
299
|
+
# However if the +:update_only+ option is +true+, the nested attributes
|
290
300
|
# are used to update the record's attributes always, regardless of
|
291
301
|
# whether the <tt>:id</tt> is present. The option is ignored for collection
|
292
302
|
# associations.
|
@@ -376,6 +386,9 @@ module ActiveRecord
|
|
376
386
|
# then the existing record will be marked for destruction.
|
377
387
|
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
|
378
388
|
options = self.nested_attributes_options[association_name]
|
389
|
+
if attributes.respond_to?(:permitted?)
|
390
|
+
attributes = attributes.to_h
|
391
|
+
end
|
379
392
|
attributes = attributes.with_indifferent_access
|
380
393
|
existing_record = send(association_name)
|
381
394
|
|
@@ -432,6 +445,9 @@ module ActiveRecord
|
|
432
445
|
# ])
|
433
446
|
def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
|
434
447
|
options = self.nested_attributes_options[association_name]
|
448
|
+
if attributes_collection.respond_to?(:permitted?)
|
449
|
+
attributes_collection = attributes_collection.to_h
|
450
|
+
end
|
435
451
|
|
436
452
|
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
|
437
453
|
raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
|
@@ -458,6 +474,9 @@ module ActiveRecord
|
|
458
474
|
end
|
459
475
|
|
460
476
|
attributes_collection.each do |attributes|
|
477
|
+
if attributes.respond_to?(:permitted?)
|
478
|
+
attributes = attributes.to_h
|
479
|
+
end
|
461
480
|
attributes = attributes.with_indifferent_access
|
462
481
|
|
463
482
|
if attributes['id'].blank?
|
@@ -516,14 +535,14 @@ module ActiveRecord
|
|
516
535
|
|
517
536
|
# Determines if a hash contains a truthy _destroy key.
|
518
537
|
def has_destroy_flag?(hash)
|
519
|
-
Type::Boolean.new.
|
538
|
+
Type::Boolean.new.cast(hash['_destroy'])
|
520
539
|
end
|
521
540
|
|
522
541
|
# Determines if a new record should be rejected by checking
|
523
542
|
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
|
524
543
|
# association and evaluates to +true+.
|
525
544
|
def reject_new_record?(association_name, attributes)
|
526
|
-
|
545
|
+
has_destroy_flag?(attributes) || call_reject_if(association_name, attributes)
|
527
546
|
end
|
528
547
|
|
529
548
|
# Determines if a record with the particular +attributes+ should be
|
@@ -532,8 +551,7 @@ module ActiveRecord
|
|
532
551
|
#
|
533
552
|
# Returns false if there is a +destroy_flag+ on the attributes.
|
534
553
|
def call_reject_if(association_name, attributes)
|
535
|
-
return false if
|
536
|
-
|
554
|
+
return false if has_destroy_flag?(attributes)
|
537
555
|
case callback = self.nested_attributes_options[association_name][:reject_if]
|
538
556
|
when Symbol
|
539
557
|
method(callback).arity == 0 ? send(callback) : send(callback, attributes)
|
@@ -542,17 +560,10 @@ module ActiveRecord
|
|
542
560
|
end
|
543
561
|
end
|
544
562
|
|
545
|
-
# Only take into account the destroy flag if <tt>:allow_destroy</tt> is true
|
546
|
-
def will_be_destroyed?(association_name, attributes)
|
547
|
-
allow_destroy?(association_name) && has_destroy_flag?(attributes)
|
548
|
-
end
|
549
|
-
|
550
|
-
def allow_destroy?(association_name)
|
551
|
-
self.nested_attributes_options[association_name][:allow_destroy]
|
552
|
-
end
|
553
|
-
|
554
563
|
def raise_nested_attributes_record_not_found!(association_name, record_id)
|
555
|
-
|
564
|
+
model = self.class._reflect_on_association(association_name).klass.name
|
565
|
+
raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
|
566
|
+
model, 'id', record_id)
|
556
567
|
end
|
557
568
|
end
|
558
569
|
end
|