activerecord 4.1.15 → 4.2.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 +4 -4
- data/CHANGELOG.md +634 -2176
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/association_scope.rb +53 -21
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +32 -44
- data/lib/active_record/associations/collection_proxy.rb +1 -10
- data/lib/active_record/associations/has_many_association.rb +60 -14
- data/lib/active_record/associations/has_many_through_association.rb +34 -23
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
- data/lib/active_record/associations/join_dependency.rb +7 -9
- data/lib/active_record/associations/preloader/association.rb +9 -5
- data/lib/active_record/associations/preloader/through_association.rb +3 -3
- data/lib/active_record/associations/preloader.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +16 -1
- data/lib/active_record/associations/through_association.rb +6 -22
- data/lib/active_record/associations.rb +58 -33
- data/lib/active_record/attribute.rb +131 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +85 -42
- data/lib/active_record/attribute_methods/primary_key.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +14 -57
- data/lib/active_record/attribute_methods/serialization.rb +12 -146
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
- data/lib/active_record/attribute_methods/write.rb +8 -23
- data/lib/active_record/attribute_methods.rb +53 -90
- data/lib/active_record/attribute_set/builder.rb +32 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attributes.rb +122 -0
- data/lib/active_record/autosave_association.rb +11 -21
- data/lib/active_record/base.rb +9 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
- data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
- data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
- data/lib/active_record/connection_adapters/column.rb +13 -244
- data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
- data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
- data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +119 -22
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -10
- data/lib/active_record/errors.rb +27 -26
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +52 -45
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +33 -8
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +34 -16
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +22 -32
- data/lib/active_record/model_schema.rb +39 -48
- data/lib/active_record/nested_attributes.rb +8 -18
- data/lib/active_record/persistence.rb +39 -22
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +1 -8
- data/lib/active_record/railtie.rb +17 -10
- data/lib/active_record/railties/databases.rake +47 -42
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +225 -92
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +28 -32
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +42 -20
- data/lib/active_record/relation/merger.rb +0 -1
- data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
- data/lib/active_record/relation/predicate_builder.rb +1 -22
- data/lib/active_record/relation/query_methods.rb +98 -62
- data/lib/active_record/relation/spawn_methods.rb +6 -7
- data/lib/active_record/relation.rb +35 -11
- data/lib/active_record/result.rb +16 -9
- data/lib/active_record/sanitization.rb +8 -1
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +51 -9
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +5 -4
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +79 -5
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +37 -5
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +35 -21
- data/lib/active_record/type/binary.rb +40 -0
- data/lib/active_record/type/boolean.rb +19 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
- data/lib/active_record/type/integer.rb +23 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +51 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +48 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/type.rb +20 -0
- data/lib/active_record/validations/uniqueness.rb +9 -23
- data/lib/active_record/validations.rb +21 -16
- data/lib/active_record.rb +2 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +71 -14
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -2,6 +2,7 @@ require 'date'
|
|
2
2
|
require 'set'
|
3
3
|
require 'bigdecimal'
|
4
4
|
require 'bigdecimal/util'
|
5
|
+
require 'active_support/core_ext/string/strip'
|
5
6
|
|
6
7
|
module ActiveRecord
|
7
8
|
module ConnectionAdapters #:nodoc:
|
@@ -15,7 +16,7 @@ module ActiveRecord
|
|
15
16
|
# are typically created by methods in TableDefinition, and added to the
|
16
17
|
# +columns+ attribute of said TableDefinition object, in order to be used
|
17
18
|
# for generating a number of table creation or table changing SQL statements.
|
18
|
-
class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type) #:nodoc:
|
19
|
+
class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type, :cast_type) #:nodoc:
|
19
20
|
|
20
21
|
def primary_key?
|
21
22
|
primary_key || type.to_sym == :primary_key
|
@@ -25,6 +26,50 @@ module ActiveRecord
|
|
25
26
|
class ChangeColumnDefinition < Struct.new(:column, :type, :options) #:nodoc:
|
26
27
|
end
|
27
28
|
|
29
|
+
class ForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
|
30
|
+
def name
|
31
|
+
options[:name]
|
32
|
+
end
|
33
|
+
|
34
|
+
def column
|
35
|
+
options[:column]
|
36
|
+
end
|
37
|
+
|
38
|
+
def primary_key
|
39
|
+
options[:primary_key] || default_primary_key
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_delete
|
43
|
+
options[:on_delete]
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_update
|
47
|
+
options[:on_update]
|
48
|
+
end
|
49
|
+
|
50
|
+
def custom_primary_key?
|
51
|
+
options[:primary_key] != default_primary_key
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def default_primary_key
|
56
|
+
"id"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module TimestampDefaultDeprecation # :nodoc:
|
61
|
+
def emit_warning_if_null_unspecified(options)
|
62
|
+
return if options.key?(:null)
|
63
|
+
|
64
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
|
65
|
+
`timestamp` was called without specifying an option for `null`. In Rails
|
66
|
+
5.0, this behavior will change to `null: false`. You should manually
|
67
|
+
specify `null: true` to prevent the behavior of your existing migrations
|
68
|
+
from changing.
|
69
|
+
MESSAGE
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
28
73
|
# Represents the schema of an SQL table in an abstract way. This class
|
29
74
|
# provides methods for manipulating the schema representation.
|
30
75
|
#
|
@@ -46,6 +91,8 @@ module ActiveRecord
|
|
46
91
|
# The table definitions
|
47
92
|
# The Columns are stored as a ColumnDefinition in the +columns+ attribute.
|
48
93
|
class TableDefinition
|
94
|
+
include TimestampDefaultDeprecation
|
95
|
+
|
49
96
|
# An array of ColumnDefinition objects, representing the column changes
|
50
97
|
# that have been defined.
|
51
98
|
attr_accessor :indexes
|
@@ -99,9 +146,11 @@ module ActiveRecord
|
|
99
146
|
# Specifies the precision for a <tt>:decimal</tt> column.
|
100
147
|
# * <tt>:scale</tt> -
|
101
148
|
# Specifies the scale for a <tt>:decimal</tt> column.
|
149
|
+
# * <tt>:index</tt> -
|
150
|
+
# Create an index for the column. Can be either <tt>true</tt> or an options hash.
|
102
151
|
#
|
103
|
-
#
|
104
|
-
#
|
152
|
+
# Note: The precision is the total number of significant digits
|
153
|
+
# and the scale is the number of digits that can be stored following
|
105
154
|
# the decimal point. For example, the number 123.45 has a precision of 5
|
106
155
|
# and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
|
107
156
|
# range from -999.99 to 999.99.
|
@@ -123,17 +172,8 @@ module ActiveRecord
|
|
123
172
|
# Default is (38,0).
|
124
173
|
# * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
|
125
174
|
# Default unknown.
|
126
|
-
# * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].
|
127
|
-
# Default (9,0). Internal types NUMERIC and DECIMAL have different
|
128
|
-
# storage rules, decimal being better.
|
129
|
-
# * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
130
|
-
# Default (38,0). WARNING Max <tt>:precision</tt>/<tt>:scale</tt> for
|
131
|
-
# NUMERIC is 19, and DECIMAL is 38.
|
132
175
|
# * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
133
176
|
# Default (38,0).
|
134
|
-
# * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
|
135
|
-
# Default (38,0).
|
136
|
-
# * OpenBase?: Documentation unclear. Claims storage in <tt>double</tt>.
|
137
177
|
#
|
138
178
|
# This method returns <tt>self</tt>.
|
139
179
|
#
|
@@ -172,18 +212,21 @@ module ActiveRecord
|
|
172
212
|
# What can be written like this with the regular calls to column:
|
173
213
|
#
|
174
214
|
# create_table :products do |t|
|
175
|
-
# t.column :shop_id,
|
176
|
-
# t.column :creator_id,
|
177
|
-
# t.column :
|
178
|
-
# t.column :
|
179
|
-
# t.column :
|
180
|
-
# t.column :
|
215
|
+
# t.column :shop_id, :integer
|
216
|
+
# t.column :creator_id, :integer
|
217
|
+
# t.column :item_number, :string
|
218
|
+
# t.column :name, :string, default: "Untitled"
|
219
|
+
# t.column :value, :string, default: "Untitled"
|
220
|
+
# t.column :created_at, :datetime
|
221
|
+
# t.column :updated_at, :datetime
|
181
222
|
# end
|
223
|
+
# add_index :products, :item_number
|
182
224
|
#
|
183
225
|
# can also be written as follows using the short-hand:
|
184
226
|
#
|
185
227
|
# create_table :products do |t|
|
186
228
|
# t.integer :shop_id, :creator_id
|
229
|
+
# t.string :item_number, index: true
|
187
230
|
# t.string :name, :value, default: "Untitled"
|
188
231
|
# t.timestamps
|
189
232
|
# end
|
@@ -219,6 +262,8 @@ module ActiveRecord
|
|
219
262
|
raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
|
220
263
|
end
|
221
264
|
|
265
|
+
index_options = options.delete(:index)
|
266
|
+
index(name, index_options.is_a?(Hash) ? index_options : {}) if index_options
|
222
267
|
@columns_hash[name] = new_column_definition(name, type, options)
|
223
268
|
self
|
224
269
|
end
|
@@ -247,16 +292,27 @@ module ActiveRecord
|
|
247
292
|
# <tt>:updated_at</tt> to the table.
|
248
293
|
def timestamps(*args)
|
249
294
|
options = args.extract_options!
|
295
|
+
emit_warning_if_null_unspecified(options)
|
250
296
|
column(:created_at, :datetime, options)
|
251
297
|
column(:updated_at, :datetime, options)
|
252
298
|
end
|
253
299
|
|
300
|
+
# Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
|
301
|
+
# <tt>references</tt> and <tt>belongs_to</tt> are acceptable. The reference column will be an +integer+
|
302
|
+
# by default, the <tt>:type</tt> option can be used to specify a different type.
|
303
|
+
#
|
304
|
+
# t.references(:user)
|
305
|
+
# t.references(:user, type: "string")
|
306
|
+
# t.belongs_to(:supplier, polymorphic: true)
|
307
|
+
#
|
308
|
+
# See SchemaStatements#add_reference
|
254
309
|
def references(*args)
|
255
310
|
options = args.extract_options!
|
256
311
|
polymorphic = options.delete(:polymorphic)
|
257
312
|
index_options = options.delete(:index)
|
313
|
+
type = options.delete(:type) || :integer
|
258
314
|
args.each do |col|
|
259
|
-
column("#{col}_id",
|
315
|
+
column("#{col}_id", type, options)
|
260
316
|
column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
|
261
317
|
index(polymorphic ? %w(id type).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
|
262
318
|
end
|
@@ -264,6 +320,7 @@ module ActiveRecord
|
|
264
320
|
alias :belongs_to :references
|
265
321
|
|
266
322
|
def new_column_definition(name, type, options) # :nodoc:
|
323
|
+
type = aliased_types[type] || type
|
267
324
|
column = create_column_definition name, type
|
268
325
|
limit = options.fetch(:limit) do
|
269
326
|
native[type][:limit] if native[type].is_a?(Hash)
|
@@ -294,18 +351,36 @@ module ActiveRecord
|
|
294
351
|
def native
|
295
352
|
@native
|
296
353
|
end
|
354
|
+
|
355
|
+
def aliased_types
|
356
|
+
HashWithIndifferentAccess.new(
|
357
|
+
timestamp: :datetime,
|
358
|
+
)
|
359
|
+
end
|
297
360
|
end
|
298
361
|
|
299
362
|
class AlterTable # :nodoc:
|
300
363
|
attr_reader :adds
|
364
|
+
attr_reader :foreign_key_adds
|
365
|
+
attr_reader :foreign_key_drops
|
301
366
|
|
302
367
|
def initialize(td)
|
303
368
|
@td = td
|
304
369
|
@adds = []
|
370
|
+
@foreign_key_adds = []
|
371
|
+
@foreign_key_drops = []
|
305
372
|
end
|
306
373
|
|
307
374
|
def name; @td.name; end
|
308
375
|
|
376
|
+
def add_foreign_key(to_table, options)
|
377
|
+
@foreign_key_adds << ForeignKeyDefinition.new(name, to_table, options)
|
378
|
+
end
|
379
|
+
|
380
|
+
def drop_foreign_key(name)
|
381
|
+
@foreign_key_drops << name
|
382
|
+
end
|
383
|
+
|
309
384
|
def add_column(name, type, options)
|
310
385
|
name = name.to_s
|
311
386
|
type = type.to_sym
|
@@ -347,6 +422,8 @@ module ActiveRecord
|
|
347
422
|
# end
|
348
423
|
#
|
349
424
|
class Table
|
425
|
+
include TimestampDefaultDeprecation
|
426
|
+
|
350
427
|
def initialize(table_name, base)
|
351
428
|
@table_name = table_name
|
352
429
|
@base = base
|
@@ -395,6 +472,7 @@ module ActiveRecord
|
|
395
472
|
#
|
396
473
|
# t.timestamps
|
397
474
|
def timestamps(options = {})
|
475
|
+
emit_warning_if_null_unspecified(options)
|
398
476
|
@base.add_timestamps(@table_name, options)
|
399
477
|
end
|
400
478
|
|
@@ -452,11 +530,14 @@ module ActiveRecord
|
|
452
530
|
end
|
453
531
|
|
454
532
|
# Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
|
455
|
-
# <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
|
533
|
+
# <tt>references</tt> and <tt>belongs_to</tt> are acceptable. The reference column will be an +integer+
|
534
|
+
# by default, the <tt>:type</tt> option can be used to specify a different type.
|
456
535
|
#
|
457
536
|
# t.references(:user)
|
537
|
+
# t.references(:user, type: "string")
|
458
538
|
# t.belongs_to(:supplier, polymorphic: true)
|
459
539
|
#
|
540
|
+
# See SchemaStatements#add_reference
|
460
541
|
def references(*args)
|
461
542
|
options = args.extract_options!
|
462
543
|
args.each do |ref_name|
|
@@ -471,6 +552,7 @@ module ActiveRecord
|
|
471
552
|
# t.remove_references(:user)
|
472
553
|
# t.remove_belongs_to(:supplier, polymorphic: true)
|
473
554
|
#
|
555
|
+
# See SchemaStatements#remove_reference
|
474
556
|
def remove_references(*args)
|
475
557
|
options = args.extract_options!
|
476
558
|
args.each do |ref_name|
|
@@ -497,6 +579,5 @@ module ActiveRecord
|
|
497
579
|
@base.native_database_types
|
498
580
|
end
|
499
581
|
end
|
500
|
-
|
501
582
|
end
|
502
583
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'ipaddr'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
module ConnectionAdapters # :nodoc:
|
5
3
|
# The goal of this module is to move Adapter specific column
|
@@ -20,19 +18,13 @@ module ActiveRecord
|
|
20
18
|
def prepare_column_options(column, types)
|
21
19
|
spec = {}
|
22
20
|
spec[:name] = column.name.inspect
|
23
|
-
|
24
|
-
|
25
|
-
# code ensures that the dumper still dumps the column as a decimal.
|
26
|
-
spec[:type] = if column.type == :integer && /^(numeric|decimal)/ =~ column.sql_type
|
27
|
-
'decimal'
|
28
|
-
else
|
29
|
-
column.type.to_s
|
30
|
-
end
|
31
|
-
spec[:limit] = column.limit.inspect if column.limit != types[column.type][:limit] && spec[:type] != 'decimal'
|
21
|
+
spec[:type] = column.type.to_s
|
22
|
+
spec[:limit] = column.limit.inspect if column.limit != types[column.type][:limit]
|
32
23
|
spec[:precision] = column.precision.inspect if column.precision
|
33
24
|
spec[:scale] = column.scale.inspect if column.scale
|
34
25
|
spec[:null] = 'false' unless column.null
|
35
|
-
spec[:default] =
|
26
|
+
spec[:default] = schema_default(column) if column.has_default?
|
27
|
+
spec.delete(:default) if spec[:default].nil?
|
36
28
|
spec
|
37
29
|
end
|
38
30
|
|
@@ -43,28 +35,12 @@ module ActiveRecord
|
|
43
35
|
|
44
36
|
private
|
45
37
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
when Date, DateTime, Time
|
51
|
-
"'#{value.to_s(:db)}'"
|
52
|
-
when Range
|
53
|
-
# infinity dumps as Infinity, which causes uninitialized constant error
|
54
|
-
value.inspect.gsub('Infinity', '::Float::INFINITY')
|
55
|
-
when IPAddr
|
56
|
-
subnet_mask = value.instance_variable_get(:@mask_addr)
|
57
|
-
|
58
|
-
# If the subnet mask is equal to /32, don't output it
|
59
|
-
if subnet_mask == (2**32 - 1)
|
60
|
-
"\"#{value.to_s}\""
|
61
|
-
else
|
62
|
-
"\"#{value.to_s}/#{subnet_mask.to_s(2).count('1')}\""
|
63
|
-
end
|
64
|
-
else
|
65
|
-
value.inspect
|
66
|
-
end
|
38
|
+
def schema_default(column)
|
39
|
+
default = column.type_cast_from_database(column.default)
|
40
|
+
unless default.nil?
|
41
|
+
column.type_cast_for_schema(default)
|
67
42
|
end
|
43
|
+
end
|
68
44
|
end
|
69
45
|
end
|
70
46
|
end
|
@@ -43,13 +43,14 @@ module ActiveRecord
|
|
43
43
|
# index_exists?(:suppliers, :company_id, name: "idx_company_id")
|
44
44
|
#
|
45
45
|
def index_exists?(table_name, column_name, options = {})
|
46
|
-
column_names = Array(column_name)
|
47
|
-
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, :
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
column_names = Array(column_name).map(&:to_s)
|
47
|
+
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, column: column_names)
|
48
|
+
checks = []
|
49
|
+
checks << lambda { |i| i.name == index_name }
|
50
|
+
checks << lambda { |i| i.columns == column_names }
|
51
|
+
checks << lambda { |i| i.unique } if options[:unique]
|
52
|
+
|
53
|
+
indexes(table_name).any? { |i| checks.all? { |check| check[i] } }
|
53
54
|
end
|
54
55
|
|
55
56
|
# Returns an array of Column objects for the table specified by +table_name+.
|
@@ -71,7 +72,8 @@ module ActiveRecord
|
|
71
72
|
# column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)
|
72
73
|
#
|
73
74
|
def column_exists?(table_name, column_name, type = nil, options = {})
|
74
|
-
|
75
|
+
column_name = column_name.to_s
|
76
|
+
columns(table_name).any?{ |c| c.name == column_name &&
|
75
77
|
(!type || c.type == type) &&
|
76
78
|
(!options.key?(:limit) || c.limit == options[:limit]) &&
|
77
79
|
(!options.key?(:precision) || c.precision == options[:precision]) &&
|
@@ -186,24 +188,23 @@ module ActiveRecord
|
|
186
188
|
def create_table(table_name, options = {})
|
187
189
|
td = create_table_definition table_name, options[:temporary], options[:options], options[:as]
|
188
190
|
|
189
|
-
if !options[:as]
|
190
|
-
|
191
|
-
|
192
|
-
Base.get_primary_key table_name.to_s.singularize
|
193
|
-
}
|
194
|
-
|
195
|
-
td.primary_key pk, options.fetch(:id, :primary_key), options
|
191
|
+
if options[:id] != false && !options[:as]
|
192
|
+
pk = options.fetch(:primary_key) do
|
193
|
+
Base.get_primary_key table_name.to_s.singularize
|
196
194
|
end
|
197
195
|
|
198
|
-
|
196
|
+
td.primary_key pk, options.fetch(:id, :primary_key), options
|
199
197
|
end
|
200
198
|
|
199
|
+
yield td if block_given?
|
200
|
+
|
201
201
|
if options[:force] && table_exists?(table_name)
|
202
202
|
drop_table(table_name, options)
|
203
203
|
end
|
204
204
|
|
205
|
-
execute schema_creation.accept td
|
206
|
-
td.indexes.each_pair { |c,o| add_index
|
205
|
+
result = execute schema_creation.accept td
|
206
|
+
td.indexes.each_pair { |c, o| add_index(table_name, c, o) } unless supports_indexes_in_create?
|
207
|
+
result
|
207
208
|
end
|
208
209
|
|
209
210
|
# Creates a new join table with the name created using the lexical order of the first two
|
@@ -602,12 +603,18 @@ module ActiveRecord
|
|
602
603
|
end
|
603
604
|
|
604
605
|
# Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
|
606
|
+
# The reference column is an +integer+ by default, the <tt>:type</tt> option can be used to specify
|
607
|
+
# a different type.
|
605
608
|
# <tt>add_reference</tt> and <tt>add_belongs_to</tt> are acceptable.
|
606
609
|
#
|
607
|
-
# ====== Create a user_id column
|
610
|
+
# ====== Create a user_id integer column
|
608
611
|
#
|
609
612
|
# add_reference(:products, :user)
|
610
613
|
#
|
614
|
+
# ====== Create a user_id string column
|
615
|
+
#
|
616
|
+
# add_reference(:products, :user, type: :string)
|
617
|
+
#
|
611
618
|
# ====== Create a supplier_id and supplier_type columns
|
612
619
|
#
|
613
620
|
# add_belongs_to(:products, :supplier, polymorphic: true)
|
@@ -619,7 +626,8 @@ module ActiveRecord
|
|
619
626
|
def add_reference(table_name, ref_name, options = {})
|
620
627
|
polymorphic = options.delete(:polymorphic)
|
621
628
|
index_options = options.delete(:index)
|
622
|
-
|
629
|
+
type = options.delete(:type) || :integer
|
630
|
+
add_column(table_name, "#{ref_name}_id", type, options)
|
623
631
|
add_column(table_name, "#{ref_name}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
|
624
632
|
add_index(table_name, polymorphic ? %w[id type].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
|
625
633
|
end
|
@@ -642,6 +650,115 @@ module ActiveRecord
|
|
642
650
|
end
|
643
651
|
alias :remove_belongs_to :remove_reference
|
644
652
|
|
653
|
+
# Returns an array of foreign keys for the given table.
|
654
|
+
# The foreign keys are represented as +ForeignKeyDefinition+ objects.
|
655
|
+
def foreign_keys(table_name)
|
656
|
+
raise NotImplementedError, "foreign_keys is not implemented"
|
657
|
+
end
|
658
|
+
|
659
|
+
# Adds a new foreign key. +from_table+ is the table with the key column,
|
660
|
+
# +to_table+ contains the referenced primary key.
|
661
|
+
#
|
662
|
+
# The foreign key will be named after the following pattern: <tt>fk_rails_<identifier></tt>.
|
663
|
+
# +identifier+ is a 10 character long random string. A custom name can be specified with
|
664
|
+
# the <tt>:name</tt> option.
|
665
|
+
#
|
666
|
+
# ====== Creating a simple foreign key
|
667
|
+
#
|
668
|
+
# add_foreign_key :articles, :authors
|
669
|
+
#
|
670
|
+
# generates:
|
671
|
+
#
|
672
|
+
# ALTER TABLE "articles" ADD CONSTRAINT articles_author_id_fk FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
|
673
|
+
#
|
674
|
+
# ====== Creating a foreign key on a specific column
|
675
|
+
#
|
676
|
+
# add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
|
677
|
+
#
|
678
|
+
# generates:
|
679
|
+
#
|
680
|
+
# ALTER TABLE "articles" ADD CONSTRAINT fk_rails_58ca3d3a82 FOREIGN KEY ("author_id") REFERENCES "users" ("lng_id")
|
681
|
+
#
|
682
|
+
# ====== Creating a cascading foreign key
|
683
|
+
#
|
684
|
+
# add_foreign_key :articles, :authors, on_delete: :cascade
|
685
|
+
#
|
686
|
+
# generates:
|
687
|
+
#
|
688
|
+
# ALTER TABLE "articles" ADD CONSTRAINT articles_author_id_fk FOREIGN KEY ("author_id") REFERENCES "authors" ("id") ON DELETE CASCADE
|
689
|
+
#
|
690
|
+
# The +options+ hash can include the following keys:
|
691
|
+
# [<tt>:column</tt>]
|
692
|
+
# The foreign key column name on +from_table+. Defaults to <tt>to_table.singularize + "_id"</tt>
|
693
|
+
# [<tt>:primary_key</tt>]
|
694
|
+
# The primary key column name on +to_table+. Defaults to +id+.
|
695
|
+
# [<tt>:name</tt>]
|
696
|
+
# The constraint name. Defaults to <tt>fk_rails_<identifier></tt>.
|
697
|
+
# [<tt>:on_delete</tt>]
|
698
|
+
# Action that happens <tt>ON DELETE</tt>. Valid values are +:nullify+, +:cascade:+ and +:restrict+
|
699
|
+
# [<tt>:on_update</tt>]
|
700
|
+
# Action that happens <tt>ON UPDATE</tt>. Valid values are +:nullify+, +:cascade:+ and +:restrict+
|
701
|
+
def add_foreign_key(from_table, to_table, options = {})
|
702
|
+
return unless supports_foreign_keys?
|
703
|
+
|
704
|
+
options[:column] ||= foreign_key_column_for(to_table)
|
705
|
+
|
706
|
+
options = {
|
707
|
+
column: options[:column],
|
708
|
+
primary_key: options[:primary_key],
|
709
|
+
name: foreign_key_name(from_table, options),
|
710
|
+
on_delete: options[:on_delete],
|
711
|
+
on_update: options[:on_update]
|
712
|
+
}
|
713
|
+
at = create_alter_table from_table
|
714
|
+
at.add_foreign_key to_table, options
|
715
|
+
|
716
|
+
execute schema_creation.accept(at)
|
717
|
+
end
|
718
|
+
|
719
|
+
# Removes the given foreign key from the table.
|
720
|
+
#
|
721
|
+
# Removes the foreign key on +accounts.branch_id+.
|
722
|
+
#
|
723
|
+
# remove_foreign_key :accounts, :branches
|
724
|
+
#
|
725
|
+
# Removes the foreign key on +accounts.owner_id+.
|
726
|
+
#
|
727
|
+
# remove_foreign_key :accounts, column: :owner_id
|
728
|
+
#
|
729
|
+
# Removes the foreign key named +special_fk_name+ on the +accounts+ table.
|
730
|
+
#
|
731
|
+
# remove_foreign_key :accounts, name: :special_fk_name
|
732
|
+
#
|
733
|
+
def remove_foreign_key(from_table, options_or_to_table = {})
|
734
|
+
return unless supports_foreign_keys?
|
735
|
+
|
736
|
+
if options_or_to_table.is_a?(Hash)
|
737
|
+
options = options_or_to_table
|
738
|
+
else
|
739
|
+
options = { column: foreign_key_column_for(options_or_to_table) }
|
740
|
+
end
|
741
|
+
|
742
|
+
fk_name_to_delete = options.fetch(:name) do
|
743
|
+
fk_to_delete = foreign_keys(from_table).detect {|fk| fk.column == options[:column] }
|
744
|
+
|
745
|
+
if fk_to_delete
|
746
|
+
fk_to_delete.name
|
747
|
+
else
|
748
|
+
raise ArgumentError, "Table '#{from_table}' has no foreign key on column '#{options[:column]}'"
|
749
|
+
end
|
750
|
+
end
|
751
|
+
|
752
|
+
at = create_alter_table from_table
|
753
|
+
at.drop_foreign_key fk_name_to_delete
|
754
|
+
|
755
|
+
execute schema_creation.accept(at)
|
756
|
+
end
|
757
|
+
|
758
|
+
def foreign_key_column_for(table_name) # :nodoc:
|
759
|
+
"#{table_name.to_s.singularize}_id"
|
760
|
+
end
|
761
|
+
|
645
762
|
def dump_schema_information #:nodoc:
|
646
763
|
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
647
764
|
|
@@ -740,6 +857,40 @@ module ActiveRecord
|
|
740
857
|
Table.new(table_name, base)
|
741
858
|
end
|
742
859
|
|
860
|
+
def add_index_options(table_name, column_name, options = {}) #:nodoc:
|
861
|
+
column_names = Array(column_name)
|
862
|
+
index_name = index_name(table_name, column: column_names)
|
863
|
+
|
864
|
+
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
|
865
|
+
|
866
|
+
index_type = options[:unique] ? "UNIQUE" : ""
|
867
|
+
index_type = options[:type].to_s if options.key?(:type)
|
868
|
+
index_name = options[:name].to_s if options.key?(:name)
|
869
|
+
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
870
|
+
|
871
|
+
if options.key?(:algorithm)
|
872
|
+
algorithm = index_algorithms.fetch(options[:algorithm]) {
|
873
|
+
raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
|
874
|
+
}
|
875
|
+
end
|
876
|
+
|
877
|
+
using = "USING #{options[:using]}" if options[:using].present?
|
878
|
+
|
879
|
+
if supports_partial_index?
|
880
|
+
index_options = options[:where] ? " WHERE #{options[:where]}" : ""
|
881
|
+
end
|
882
|
+
|
883
|
+
if index_name.length > max_index_length
|
884
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
|
885
|
+
end
|
886
|
+
if table_exists?(table_name) && index_name_exists?(table_name, index_name, false)
|
887
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
888
|
+
end
|
889
|
+
index_columns = quoted_columns_for_index(column_names, options).join(", ")
|
890
|
+
|
891
|
+
[index_name, index_type, index_columns, index_options, algorithm, using]
|
892
|
+
end
|
893
|
+
|
743
894
|
protected
|
744
895
|
def add_index_sort_order(option_strings, column_names, options = {})
|
745
896
|
if options.is_a?(Hash) && order = options[:order]
|
@@ -754,7 +905,7 @@ module ActiveRecord
|
|
754
905
|
return option_strings
|
755
906
|
end
|
756
907
|
|
757
|
-
# Overridden by the
|
908
|
+
# Overridden by the MySQL adapter for supporting index lengths
|
758
909
|
def quoted_columns_for_index(column_names, options = {})
|
759
910
|
option_strings = Hash[column_names.map {|name| [name, '']}]
|
760
911
|
|
@@ -770,40 +921,6 @@ module ActiveRecord
|
|
770
921
|
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
|
771
922
|
end
|
772
923
|
|
773
|
-
def add_index_options(table_name, column_name, options = {})
|
774
|
-
column_names = Array(column_name)
|
775
|
-
index_name = index_name(table_name, column: column_names)
|
776
|
-
|
777
|
-
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
|
778
|
-
|
779
|
-
index_type = options[:unique] ? "UNIQUE" : ""
|
780
|
-
index_type = options[:type].to_s if options.key?(:type)
|
781
|
-
index_name = options[:name].to_s if options.key?(:name)
|
782
|
-
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
783
|
-
|
784
|
-
if options.key?(:algorithm)
|
785
|
-
algorithm = index_algorithms.fetch(options[:algorithm]) {
|
786
|
-
raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
|
787
|
-
}
|
788
|
-
end
|
789
|
-
|
790
|
-
using = "USING #{options[:using]}" if options[:using].present?
|
791
|
-
|
792
|
-
if supports_partial_index?
|
793
|
-
index_options = options[:where] ? " WHERE #{options[:where]}" : ""
|
794
|
-
end
|
795
|
-
|
796
|
-
if index_name.length > max_index_length
|
797
|
-
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
|
798
|
-
end
|
799
|
-
if index_name_exists?(table_name, index_name, false)
|
800
|
-
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
801
|
-
end
|
802
|
-
index_columns = quoted_columns_for_index(column_names, options).join(", ")
|
803
|
-
|
804
|
-
[index_name, index_type, index_columns, index_options, algorithm, using]
|
805
|
-
end
|
806
|
-
|
807
924
|
def index_name_for_remove(table_name, options = {})
|
808
925
|
index_name = index_name(table_name, options)
|
809
926
|
|
@@ -852,6 +969,12 @@ module ActiveRecord
|
|
852
969
|
def create_alter_table(name)
|
853
970
|
AlterTable.new create_table_definition(name, false, {})
|
854
971
|
end
|
972
|
+
|
973
|
+
def foreign_key_name(table_name, options) # :nodoc:
|
974
|
+
options.fetch(:name) do
|
975
|
+
"fk_rails_#{SecureRandom.hex(5)}"
|
976
|
+
end
|
977
|
+
end
|
855
978
|
end
|
856
979
|
end
|
857
980
|
end
|