activerecord 4.0.0.beta1 → 4.0.0.rc1
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 +573 -30
- data/README.rdoc +3 -3
- data/lib/active_record.rb +8 -2
- data/lib/active_record/associations.rb +16 -9
- data/lib/active_record/associations/association.rb +8 -6
- data/lib/active_record/associations/association_scope.rb +2 -1
- data/lib/active_record/associations/belongs_to_association.rb +2 -2
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/belongs_to.rb +37 -5
- data/lib/active_record/associations/collection_association.rb +38 -14
- data/lib/active_record/associations/collection_proxy.rb +18 -15
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +3 -3
- data/lib/active_record/associations/has_many_association.rb +4 -3
- data/lib/active_record/associations/has_many_through_association.rb +1 -1
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +29 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +26 -6
- data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_part.rb +6 -6
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +5 -5
- data/lib/active_record/attribute_methods.rb +20 -5
- data/lib/active_record/attribute_methods/dirty.rb +5 -1
- data/lib/active_record/attribute_methods/primary_key.rb +1 -1
- data/lib/active_record/attribute_methods/serialization.rb +9 -2
- data/lib/active_record/autosave_association.rb +19 -5
- data/lib/active_record/base.rb +3 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +8 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +3 -9
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +2 -8
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +60 -61
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +291 -153
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +92 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +55 -29
- data/lib/active_record/connection_adapters/column.rb +4 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -3
- data/lib/active_record/connection_adapters/mysql_adapter.rb +5 -5
- data/lib/active_record/connection_adapters/postgresql/cast.rb +22 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +50 -9
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +53 -24
- data/lib/active_record/connection_adapters/schema_cache.rb +35 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -5
- data/lib/active_record/connection_handling.rb +7 -7
- data/lib/active_record/core.rb +43 -8
- data/lib/active_record/counter_cache.rb +2 -1
- data/lib/active_record/errors.rb +11 -10
- data/lib/active_record/explain.rb +9 -7
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +3 -2
- data/lib/active_record/fixture_set/file.rb +1 -2
- data/lib/active_record/fixtures.rb +13 -7
- data/lib/active_record/inheritance.rb +12 -4
- data/lib/active_record/integration.rb +3 -3
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/log_subscriber.rb +2 -2
- data/lib/active_record/migration.rb +69 -21
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/nested_attributes.rb +98 -46
- data/lib/active_record/persistence.rb +3 -3
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +18 -4
- data/lib/active_record/railties/console_sandbox.rb +3 -2
- data/lib/active_record/railties/controller_runtime.rb +2 -1
- data/lib/active_record/railties/databases.rake +38 -80
- data/lib/active_record/reflection.rb +36 -3
- data/lib/active_record/relation.rb +18 -8
- data/lib/active_record/relation/calculations.rb +10 -5
- data/lib/active_record/relation/delegation.rb +3 -5
- data/lib/active_record/relation/finder_methods.rb +27 -14
- data/lib/active_record/relation/merger.rb +30 -2
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_methods.rb +113 -16
- data/lib/active_record/runtime_registry.rb +17 -0
- data/lib/active_record/schema_dumper.rb +5 -1
- data/lib/active_record/schema_migration.rb +8 -5
- data/lib/active_record/scoping.rb +56 -2
- data/lib/active_record/scoping/default.rb +12 -11
- data/lib/active_record/scoping/named.rb +7 -3
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/statement_cache.rb +26 -0
- data/lib/active_record/tasks/database_tasks.rb +55 -10
- data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +7 -2
- data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
- data/lib/active_record/timestamp.rb +6 -0
- data/lib/active_record/transactions.rb +7 -3
- data/lib/active_record/validations.rb +1 -2
- data/lib/active_record/validations/uniqueness.rb +7 -3
- data/lib/active_record/version.rb +7 -6
- data/lib/rails/generators/active_record/migration/migration_generator.rb +9 -2
- data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +4 -1
- metadata +17 -12
- data/examples/associations.png +0 -0
@@ -1,10 +1,12 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters # :nodoc:
|
3
5
|
# The goal of this module is to move Adapter specific column
|
4
6
|
# definitions to the Adapter instead of having it in the schema
|
5
7
|
# dumper itself. This code represents the normal case.
|
6
|
-
# We can then redefine how certain data types may be handled in the schema dumper on the
|
7
|
-
# Adapter level by over-writing this code inside the database
|
8
|
+
# We can then redefine how certain data types may be handled in the schema dumper on the
|
9
|
+
# Adapter level by over-writing this code inside the database specific adapters
|
8
10
|
module ColumnDumper
|
9
11
|
def column_spec(column, types)
|
10
12
|
spec = prepare_column_options(column, types)
|
@@ -50,6 +52,15 @@ module ActiveRecord
|
|
50
52
|
when Range
|
51
53
|
# infinity dumps as Infinity, which causes uninitialized constant error
|
52
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
|
53
64
|
else
|
54
65
|
value.inspect
|
55
66
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
module SchemaStatements
|
6
6
|
include ActiveRecord::Migration::JoinTable
|
7
7
|
|
8
|
-
# Returns a
|
8
|
+
# Returns a hash of mappings from the abstract data types to the native
|
9
9
|
# database types. See TableDefinition#column for details on the recognized
|
10
10
|
# abstract data types.
|
11
11
|
def native_database_types
|
@@ -20,6 +20,7 @@ module ActiveRecord
|
|
20
20
|
# Checks to see if the table +table_name+ exists on the database.
|
21
21
|
#
|
22
22
|
# table_exists?(:developers)
|
23
|
+
#
|
23
24
|
def table_exists?(table_name)
|
24
25
|
tables.include?(table_name.to_s)
|
25
26
|
end
|
@@ -29,17 +30,18 @@ module ActiveRecord
|
|
29
30
|
|
30
31
|
# Checks to see if an index exists on a table for a given index definition.
|
31
32
|
#
|
32
|
-
#
|
33
|
-
#
|
33
|
+
# # Check an index exists
|
34
|
+
# index_exists?(:suppliers, :company_id)
|
35
|
+
#
|
36
|
+
# # Check an index on multiple columns exists
|
37
|
+
# index_exists?(:suppliers, [:company_id, :company_type])
|
34
38
|
#
|
35
|
-
#
|
36
|
-
#
|
39
|
+
# # Check a unique index exists
|
40
|
+
# index_exists?(:suppliers, :company_id, unique: true)
|
37
41
|
#
|
38
|
-
#
|
39
|
-
#
|
42
|
+
# # Check an index with a custom name exists
|
43
|
+
# index_exists?(:suppliers, :company_id, name: "idx_company_id"
|
40
44
|
#
|
41
|
-
# # Check an index with a custom name exists
|
42
|
-
# index_exists?(:suppliers, :company_id, name: "idx_company_id"
|
43
45
|
def index_exists?(table_name, column_name, options = {})
|
44
46
|
column_names = Array(column_name)
|
45
47
|
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, :column => column_names)
|
@@ -56,17 +58,18 @@ module ActiveRecord
|
|
56
58
|
|
57
59
|
# Checks to see if a column exists in a given table.
|
58
60
|
#
|
59
|
-
#
|
60
|
-
#
|
61
|
+
# # Check a column exists
|
62
|
+
# column_exists?(:suppliers, :name)
|
63
|
+
#
|
64
|
+
# # Check a column exists of a particular type
|
65
|
+
# column_exists?(:suppliers, :name, :string)
|
61
66
|
#
|
62
|
-
#
|
63
|
-
#
|
67
|
+
# # Check a column exists with a specific definition
|
68
|
+
# column_exists?(:suppliers, :name, :string, limit: 100)
|
69
|
+
# column_exists?(:suppliers, :name, :string, default: 'default')
|
70
|
+
# column_exists?(:suppliers, :name, :string, null: false)
|
71
|
+
# column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)
|
64
72
|
#
|
65
|
-
# # Check a column exists with a specific definition
|
66
|
-
# column_exists?(:suppliers, :name, :string, limit: 100)
|
67
|
-
# column_exists?(:suppliers, :name, :string, default: 'default')
|
68
|
-
# column_exists?(:suppliers, :name, :string, null: false)
|
69
|
-
# column_exists?(:suppliers, :tax, :decimal, precision: 8, scale: 2)
|
70
73
|
def column_exists?(table_name, column_name, type = nil, options = {})
|
71
74
|
columns(table_name).any?{ |c| c.name == column_name.to_s &&
|
72
75
|
(!type || c.type == type) &&
|
@@ -84,27 +87,30 @@ module ActiveRecord
|
|
84
87
|
# form or the regular form, like this:
|
85
88
|
#
|
86
89
|
# === Block form
|
87
|
-
# # create_table() passes a TableDefinition object to the block.
|
88
|
-
# # This form will not only create the table, but also columns for the
|
89
|
-
# # table.
|
90
90
|
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
91
|
+
# # create_table() passes a TableDefinition object to the block.
|
92
|
+
# # This form will not only create the table, but also columns for the
|
93
|
+
# # table.
|
94
|
+
#
|
95
|
+
# create_table(:suppliers) do |t|
|
96
|
+
# t.column :name, :string, limit: 60
|
97
|
+
# # Other fields here
|
98
|
+
# end
|
95
99
|
#
|
96
100
|
# === Block form, with shorthand
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
101
|
+
#
|
102
|
+
# # You can also use the column types as method calls, rather than calling the column method.
|
103
|
+
# create_table(:suppliers) do |t|
|
104
|
+
# t.string :name, limit: 60
|
105
|
+
# # Other fields here
|
106
|
+
# end
|
102
107
|
#
|
103
108
|
# === Regular form
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
109
|
+
#
|
110
|
+
# # Creates a table called 'suppliers' with no columns.
|
111
|
+
# create_table(:suppliers)
|
112
|
+
# # Add a column to 'suppliers'.
|
113
|
+
# add_column(:suppliers, :name, :string, {limit: 60})
|
108
114
|
#
|
109
115
|
# The +options+ hash can include the following keys:
|
110
116
|
# [<tt>:id</tt>]
|
@@ -127,37 +133,53 @@ module ActiveRecord
|
|
127
133
|
# Defaults to false.
|
128
134
|
#
|
129
135
|
# ====== Add a backend specific option to the generated SQL (MySQL)
|
130
|
-
#
|
136
|
+
#
|
137
|
+
# create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
|
138
|
+
#
|
131
139
|
# generates:
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
140
|
+
#
|
141
|
+
# CREATE TABLE suppliers (
|
142
|
+
# id int(11) DEFAULT NULL auto_increment PRIMARY KEY
|
143
|
+
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
135
144
|
#
|
136
145
|
# ====== Rename the primary key column
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
146
|
+
#
|
147
|
+
# create_table(:objects, primary_key: 'guid') do |t|
|
148
|
+
# t.column :name, :string, limit: 80
|
149
|
+
# end
|
150
|
+
#
|
140
151
|
# generates:
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
#
|
152
|
+
#
|
153
|
+
# CREATE TABLE objects (
|
154
|
+
# guid int(11) DEFAULT NULL auto_increment PRIMARY KEY,
|
155
|
+
# name varchar(80)
|
156
|
+
# )
|
145
157
|
#
|
146
158
|
# ====== Do not add a primary key column
|
147
|
-
#
|
148
|
-
#
|
149
|
-
#
|
150
|
-
#
|
159
|
+
#
|
160
|
+
# create_table(:categories_suppliers, id: false) do |t|
|
161
|
+
# t.column :category_id, :integer
|
162
|
+
# t.column :supplier_id, :integer
|
163
|
+
# end
|
164
|
+
#
|
151
165
|
# generates:
|
152
|
-
#
|
153
|
-
#
|
154
|
-
#
|
155
|
-
#
|
166
|
+
#
|
167
|
+
# CREATE TABLE categories_suppliers (
|
168
|
+
# category_id int,
|
169
|
+
# supplier_id int
|
170
|
+
# )
|
156
171
|
#
|
157
172
|
# See also TableDefinition#column for details on how to create columns.
|
158
173
|
def create_table(table_name, options = {})
|
159
|
-
td =
|
160
|
-
|
174
|
+
td = create_table_definition table_name, options[:temporary], options[:options]
|
175
|
+
|
176
|
+
unless options[:id] == false
|
177
|
+
pk = options.fetch(:primary_key) {
|
178
|
+
Base.get_primary_key table_name.to_s.singularize
|
179
|
+
}
|
180
|
+
|
181
|
+
td.primary_key pk, options.fetch(:id, :primary_key), options
|
182
|
+
end
|
161
183
|
|
162
184
|
yield td if block_given?
|
163
185
|
|
@@ -165,19 +187,15 @@ module ActiveRecord
|
|
165
187
|
drop_table(table_name, options)
|
166
188
|
end
|
167
189
|
|
168
|
-
|
169
|
-
create_sql << "#{quote_table_name(table_name)} ("
|
170
|
-
create_sql << td.to_sql
|
171
|
-
create_sql << ") #{options[:options]}"
|
172
|
-
execute create_sql
|
190
|
+
execute schema_creation.accept td
|
173
191
|
td.indexes.each_pair { |c,o| add_index table_name, c, o }
|
174
192
|
end
|
175
193
|
|
176
194
|
# Creates a new join table with the name created using the lexical order of the first two
|
177
195
|
# arguments. These arguments can be a String or a Symbol.
|
178
196
|
#
|
179
|
-
#
|
180
|
-
#
|
197
|
+
# # Creates a table called 'assemblies_parts' with no id.
|
198
|
+
# create_join_table(:assemblies, :parts)
|
181
199
|
#
|
182
200
|
# You can pass a +options+ hash can include the following keys:
|
183
201
|
# [<tt>:table_name</tt>]
|
@@ -201,12 +219,16 @@ module ActiveRecord
|
|
201
219
|
# end
|
202
220
|
#
|
203
221
|
# ====== Add a backend specific option to the generated SQL (MySQL)
|
204
|
-
#
|
222
|
+
#
|
223
|
+
# create_join_table(:assemblies, :parts, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
|
224
|
+
#
|
205
225
|
# generates:
|
206
|
-
#
|
207
|
-
#
|
208
|
-
#
|
209
|
-
#
|
226
|
+
#
|
227
|
+
# CREATE TABLE assemblies_parts (
|
228
|
+
# assembly_id int NOT NULL,
|
229
|
+
# part_id int NOT NULL,
|
230
|
+
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
231
|
+
#
|
210
232
|
def create_join_table(table_1, table_2, options = {})
|
211
233
|
join_table_name = find_join_table_name(table_1, table_2, options)
|
212
234
|
|
@@ -223,7 +245,7 @@ module ActiveRecord
|
|
223
245
|
end
|
224
246
|
|
225
247
|
# Drops the join table specified by the given arguments.
|
226
|
-
# See create_join_table for details.
|
248
|
+
# See +create_join_table+ for details.
|
227
249
|
#
|
228
250
|
# Although this command ignores the block if one is given, it can be helpful
|
229
251
|
# to provide one in a migration's +change+ method so it can be reverted.
|
@@ -235,79 +257,88 @@ module ActiveRecord
|
|
235
257
|
|
236
258
|
# A block for changing columns in +table+.
|
237
259
|
#
|
238
|
-
#
|
239
|
-
#
|
240
|
-
#
|
241
|
-
#
|
242
|
-
#
|
260
|
+
# # change_table() yields a Table instance
|
261
|
+
# change_table(:suppliers) do |t|
|
262
|
+
# t.column :name, :string, limit: 60
|
263
|
+
# # Other column alterations here
|
264
|
+
# end
|
243
265
|
#
|
244
266
|
# The +options+ hash can include the following keys:
|
245
267
|
# [<tt>:bulk</tt>]
|
246
268
|
# Set this to true to make this a bulk alter query, such as
|
247
|
-
#
|
269
|
+
#
|
270
|
+
# ALTER TABLE `users` ADD COLUMN age INT(11), ADD COLUMN birthdate DATETIME ...
|
248
271
|
#
|
249
272
|
# Defaults to false.
|
250
273
|
#
|
251
274
|
# ====== Add a column
|
252
|
-
#
|
253
|
-
#
|
254
|
-
#
|
275
|
+
#
|
276
|
+
# change_table(:suppliers) do |t|
|
277
|
+
# t.column :name, :string, limit: 60
|
278
|
+
# end
|
255
279
|
#
|
256
280
|
# ====== Add 2 integer columns
|
257
|
-
#
|
258
|
-
#
|
259
|
-
#
|
281
|
+
#
|
282
|
+
# change_table(:suppliers) do |t|
|
283
|
+
# t.integer :width, :height, null: false, default: 0
|
284
|
+
# end
|
260
285
|
#
|
261
286
|
# ====== Add created_at/updated_at columns
|
262
|
-
#
|
263
|
-
#
|
264
|
-
#
|
287
|
+
#
|
288
|
+
# change_table(:suppliers) do |t|
|
289
|
+
# t.timestamps
|
290
|
+
# end
|
265
291
|
#
|
266
292
|
# ====== Add a foreign key column
|
267
|
-
# change_table(:suppliers) do |t|
|
268
|
-
# t.references :company
|
269
|
-
# end
|
270
293
|
#
|
271
|
-
#
|
294
|
+
# change_table(:suppliers) do |t|
|
295
|
+
# t.references :company
|
296
|
+
# end
|
297
|
+
#
|
298
|
+
# Creates a <tt>company_id(integer)</tt> column.
|
272
299
|
#
|
273
300
|
# ====== Add a polymorphic foreign key column
|
301
|
+
#
|
274
302
|
# change_table(:suppliers) do |t|
|
275
303
|
# t.belongs_to :company, polymorphic: true
|
276
304
|
# end
|
277
305
|
#
|
278
|
-
# Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns
|
306
|
+
# Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns.
|
279
307
|
#
|
280
308
|
# ====== Remove a column
|
309
|
+
#
|
281
310
|
# change_table(:suppliers) do |t|
|
282
311
|
# t.remove :company
|
283
312
|
# end
|
284
313
|
#
|
285
314
|
# ====== Remove several columns
|
315
|
+
#
|
286
316
|
# change_table(:suppliers) do |t|
|
287
317
|
# t.remove :company_id
|
288
318
|
# t.remove :width, :height
|
289
319
|
# end
|
290
320
|
#
|
291
321
|
# ====== Remove an index
|
322
|
+
#
|
292
323
|
# change_table(:suppliers) do |t|
|
293
324
|
# t.remove_index :company_id
|
294
325
|
# end
|
295
326
|
#
|
296
|
-
# See also Table for details on
|
297
|
-
# all of the various column transformation
|
327
|
+
# See also Table for details on all of the various column transformation.
|
298
328
|
def change_table(table_name, options = {})
|
299
329
|
if supports_bulk_alter? && options[:bulk]
|
300
330
|
recorder = ActiveRecord::Migration::CommandRecorder.new(self)
|
301
|
-
yield
|
331
|
+
yield update_table_definition(table_name, recorder)
|
302
332
|
bulk_change_table(table_name, recorder.commands)
|
303
333
|
else
|
304
|
-
yield
|
334
|
+
yield update_table_definition(table_name, self)
|
305
335
|
end
|
306
336
|
end
|
307
337
|
|
308
338
|
# Renames a table.
|
309
339
|
#
|
310
|
-
#
|
340
|
+
# rename_table('octopuses', 'octopi')
|
341
|
+
#
|
311
342
|
def rename_table(table_name, new_name)
|
312
343
|
raise NotImplementedError, "rename_table is not implemented"
|
313
344
|
end
|
@@ -324,14 +355,15 @@ module ActiveRecord
|
|
324
355
|
# Adds a new column to the named table.
|
325
356
|
# See TableDefinition#column for details of the options you can use.
|
326
357
|
def add_column(table_name, column_name, type, options = {})
|
327
|
-
|
328
|
-
|
329
|
-
execute
|
358
|
+
at = create_alter_table table_name
|
359
|
+
at.add_column(column_name, type, options)
|
360
|
+
execute schema_creation.accept at
|
330
361
|
end
|
331
362
|
|
332
363
|
# Removes the given columns from the table definition.
|
333
364
|
#
|
334
|
-
#
|
365
|
+
# remove_columns(:suppliers, :qualification, :experience)
|
366
|
+
#
|
335
367
|
def remove_columns(table_name, *column_names)
|
336
368
|
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)") if column_names.empty?
|
337
369
|
column_names.each do |column_name|
|
@@ -341,7 +373,7 @@ module ActiveRecord
|
|
341
373
|
|
342
374
|
# Removes the column from the table definition.
|
343
375
|
#
|
344
|
-
#
|
376
|
+
# remove_column(:suppliers, :qualification)
|
345
377
|
#
|
346
378
|
# The +type+ and +options+ parameters will be ignored if present. It can be helpful
|
347
379
|
# to provide these in a migration's +change+ method so it can be reverted.
|
@@ -353,24 +385,50 @@ module ActiveRecord
|
|
353
385
|
# Changes the column's definition according to the new options.
|
354
386
|
# See TableDefinition#column for details of the options you can use.
|
355
387
|
#
|
356
|
-
#
|
357
|
-
#
|
388
|
+
# change_column(:suppliers, :name, :string, limit: 80)
|
389
|
+
# change_column(:accounts, :description, :text)
|
390
|
+
#
|
358
391
|
def change_column(table_name, column_name, type, options = {})
|
359
392
|
raise NotImplementedError, "change_column is not implemented"
|
360
393
|
end
|
361
394
|
|
362
|
-
# Sets a new default value for a column
|
395
|
+
# Sets a new default value for a column:
|
396
|
+
#
|
397
|
+
# change_column_default(:suppliers, :qualification, 'new')
|
398
|
+
# change_column_default(:accounts, :authorized, 1)
|
399
|
+
#
|
400
|
+
# Setting the default to +nil+ effectively drops the default:
|
401
|
+
#
|
402
|
+
# change_column_default(:users, :email, nil)
|
363
403
|
#
|
364
|
-
# change_column_default(:suppliers, :qualification, 'new')
|
365
|
-
# change_column_default(:accounts, :authorized, 1)
|
366
|
-
# change_column_default(:users, :email, nil)
|
367
404
|
def change_column_default(table_name, column_name, default)
|
368
405
|
raise NotImplementedError, "change_column_default is not implemented"
|
369
406
|
end
|
370
407
|
|
408
|
+
# Sets or removes a +NOT NULL+ constraint on a column. The +null+ flag
|
409
|
+
# indicates whether the value can be +NULL+. For example
|
410
|
+
#
|
411
|
+
# change_column_null(:users, :nickname, false)
|
412
|
+
#
|
413
|
+
# says nicknames cannot be +NULL+ (adds the constraint), whereas
|
414
|
+
#
|
415
|
+
# change_column_null(:users, :nickname, true)
|
416
|
+
#
|
417
|
+
# allows them to be +NULL+ (drops the constraint).
|
418
|
+
#
|
419
|
+
# The method accepts an optional fourth argument to replace existing
|
420
|
+
# +NULL+s with some other value. Use that one when enabling the
|
421
|
+
# constraint if needed, since otherwise those rows would not be valid.
|
422
|
+
#
|
423
|
+
# Please note the fourth argument does not set a column's default.
|
424
|
+
def change_column_null(table_name, column_name, null, default = nil)
|
425
|
+
raise NotImplementedError, "change_column_null is not implemented"
|
426
|
+
end
|
427
|
+
|
371
428
|
# Renames a column.
|
372
429
|
#
|
373
|
-
#
|
430
|
+
# rename_column(:suppliers, :description, :name)
|
431
|
+
#
|
374
432
|
def rename_column(table_name, column_name, new_column_name)
|
375
433
|
raise NotImplementedError, "rename_column is not implemented"
|
376
434
|
end
|
@@ -382,60 +440,106 @@ module ActiveRecord
|
|
382
440
|
# you pass <tt>:name</tt> as an option.
|
383
441
|
#
|
384
442
|
# ====== Creating a simple index
|
385
|
-
#
|
386
|
-
#
|
387
|
-
#
|
443
|
+
#
|
444
|
+
# add_index(:suppliers, :name)
|
445
|
+
#
|
446
|
+
# generates:
|
447
|
+
#
|
448
|
+
# CREATE INDEX suppliers_name_index ON suppliers(name)
|
388
449
|
#
|
389
450
|
# ====== Creating a unique index
|
390
|
-
#
|
391
|
-
#
|
392
|
-
#
|
451
|
+
#
|
452
|
+
# add_index(:accounts, [:branch_id, :party_id], unique: true)
|
453
|
+
#
|
454
|
+
# generates:
|
455
|
+
#
|
456
|
+
# CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
|
393
457
|
#
|
394
458
|
# ====== Creating a named index
|
395
|
-
#
|
396
|
-
#
|
459
|
+
#
|
460
|
+
# add_index(:accounts, [:branch_id, :party_id], unique: true, name: 'by_branch_party')
|
461
|
+
#
|
462
|
+
# generates:
|
463
|
+
#
|
397
464
|
# CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
|
398
465
|
#
|
399
466
|
# ====== Creating an index with specific key length
|
400
|
-
# add_index(:accounts, :name, name: 'by_name', length: 10)
|
401
|
-
# generates
|
402
|
-
# CREATE INDEX by_name ON accounts(name(10))
|
403
467
|
#
|
404
|
-
#
|
405
|
-
#
|
406
|
-
#
|
468
|
+
# add_index(:accounts, :name, name: 'by_name', length: 10)
|
469
|
+
#
|
470
|
+
# generates:
|
471
|
+
#
|
472
|
+
# CREATE INDEX by_name ON accounts(name(10))
|
473
|
+
#
|
474
|
+
# add_index(:accounts, [:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15})
|
475
|
+
#
|
476
|
+
# generates:
|
477
|
+
#
|
478
|
+
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
|
407
479
|
#
|
408
|
-
# Note: SQLite doesn't support index length
|
480
|
+
# Note: SQLite doesn't support index length.
|
409
481
|
#
|
410
482
|
# ====== Creating an index with a sort order (desc or asc, asc is the default)
|
411
|
-
# add_index(:accounts, [:branch_id, :party_id, :surname], order: {branch_id: :desc, party_id: :asc})
|
412
|
-
# generates
|
413
|
-
# CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
|
414
483
|
#
|
415
|
-
#
|
484
|
+
# add_index(:accounts, [:branch_id, :party_id, :surname], order: {branch_id: :desc, party_id: :asc})
|
485
|
+
#
|
486
|
+
# generates:
|
487
|
+
#
|
488
|
+
# CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
|
489
|
+
#
|
490
|
+
# Note: MySQL doesn't yet support index order (it accepts the syntax but ignores it).
|
416
491
|
#
|
417
492
|
# ====== Creating a partial index
|
418
|
-
# add_index(:accounts, [:branch_id, :party_id], unique: true, where: "active")
|
419
|
-
# generates
|
420
|
-
# CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
|
421
493
|
#
|
422
|
-
#
|
494
|
+
# add_index(:accounts, [:branch_id, :party_id], unique: true, where: "active")
|
495
|
+
#
|
496
|
+
# generates:
|
497
|
+
#
|
498
|
+
# CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
|
499
|
+
#
|
500
|
+
# ====== Creating an index with a specific method
|
501
|
+
#
|
502
|
+
# add_index(:developers, :name, using: 'btree')
|
503
|
+
#
|
504
|
+
# generates:
|
505
|
+
#
|
506
|
+
# CREATE INDEX index_developers_on_name ON developers USING btree (name) -- PostgreSQL
|
507
|
+
# CREATE INDEX index_developers_on_name USING btree ON developers (name) -- MySQL
|
508
|
+
#
|
509
|
+
# Note: only supported by PostgreSQL and MySQL
|
510
|
+
#
|
511
|
+
# ====== Creating an index with a specific type
|
512
|
+
#
|
513
|
+
# add_index(:developers, :name, type: :fulltext)
|
423
514
|
#
|
515
|
+
# generates:
|
516
|
+
#
|
517
|
+
# CREATE FULLTEXT INDEX index_developers_on_name ON developers (name) -- MySQL
|
518
|
+
#
|
519
|
+
# Note: only supported by MySQL. Supported: <tt>:fulltext</tt> and <tt>:spatial</tt> on MyISAM tables.
|
424
520
|
def add_index(table_name, column_name, options = {})
|
425
521
|
index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
|
426
522
|
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
|
427
523
|
end
|
428
524
|
|
429
|
-
#
|
525
|
+
# Removes the given index from the table.
|
526
|
+
#
|
527
|
+
# Removes the +index_accounts_on_column+ in the +accounts+ table.
|
430
528
|
#
|
431
|
-
# Remove the index_accounts_on_column in the accounts table.
|
432
529
|
# remove_index :accounts, :column
|
433
|
-
#
|
530
|
+
#
|
531
|
+
# Removes the index named +index_accounts_on_branch_id+ in the +accounts+ table.
|
532
|
+
#
|
434
533
|
# remove_index :accounts, column: :branch_id
|
435
|
-
#
|
534
|
+
#
|
535
|
+
# Removes the index named +index_accounts_on_branch_id_and_party_id+ in the +accounts+ table.
|
536
|
+
#
|
436
537
|
# remove_index :accounts, column: [:branch_id, :party_id]
|
437
|
-
#
|
538
|
+
#
|
539
|
+
# Removes the index named +by_branch_party+ in the +accounts+ table.
|
540
|
+
#
|
438
541
|
# remove_index :accounts, name: :by_branch_party
|
542
|
+
#
|
439
543
|
def remove_index(table_name, options = {})
|
440
544
|
remove_index!(table_name, index_name_for_remove(table_name, options))
|
441
545
|
end
|
@@ -444,10 +548,12 @@ module ActiveRecord
|
|
444
548
|
execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
|
445
549
|
end
|
446
550
|
|
447
|
-
#
|
551
|
+
# Renames an index.
|
552
|
+
#
|
553
|
+
# Rename the +index_people_on_last_name+ index to +index_users_on_last_name+:
|
448
554
|
#
|
449
|
-
# Rename the index_people_on_last_name index to index_users_on_last_name
|
450
555
|
# rename_index :people, 'index_people_on_last_name', 'index_users_on_last_name'
|
556
|
+
#
|
451
557
|
def rename_index(table_name, old_name, new_name)
|
452
558
|
# this is a naive implementation; some DBs may support this more efficiently (Postgres, for instance)
|
453
559
|
old_index_def = indexes(table_name).detect { |i| i.name == old_name }
|
@@ -470,7 +576,7 @@ module ActiveRecord
|
|
470
576
|
end
|
471
577
|
end
|
472
578
|
|
473
|
-
#
|
579
|
+
# Verifies the existence of an index with a given name.
|
474
580
|
#
|
475
581
|
# The default argument is returned if the underlying implementation does not define the indexes method,
|
476
582
|
# as there's no way to determine the correct answer in that case.
|
@@ -484,13 +590,16 @@ module ActiveRecord
|
|
484
590
|
# <tt>add_reference</tt> and <tt>add_belongs_to</tt> are acceptable.
|
485
591
|
#
|
486
592
|
# ====== Create a user_id column
|
487
|
-
#
|
593
|
+
#
|
594
|
+
# add_reference(:products, :user)
|
488
595
|
#
|
489
596
|
# ====== Create a supplier_id and supplier_type columns
|
490
|
-
#
|
597
|
+
#
|
598
|
+
# add_belongs_to(:products, :supplier, polymorphic: true)
|
491
599
|
#
|
492
600
|
# ====== Create a supplier_id, supplier_type columns and appropriate index
|
493
|
-
#
|
601
|
+
#
|
602
|
+
# add_reference(:products, :supplier, polymorphic: true, index: true)
|
494
603
|
#
|
495
604
|
def add_reference(table_name, ref_name, options = {})
|
496
605
|
polymorphic = options.delete(:polymorphic)
|
@@ -505,10 +614,12 @@ module ActiveRecord
|
|
505
614
|
# <tt>remove_reference</tt>, <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
|
506
615
|
#
|
507
616
|
# ====== Remove the reference
|
508
|
-
#
|
617
|
+
#
|
618
|
+
# remove_reference(:products, :user, index: true)
|
509
619
|
#
|
510
620
|
# ====== Remove polymorphic reference
|
511
|
-
#
|
621
|
+
#
|
622
|
+
# remove_reference(:products, :supplier, polymorphic: true)
|
512
623
|
#
|
513
624
|
def remove_reference(table_name, ref_name, options = {})
|
514
625
|
remove_column(table_name, "#{ref_name}_id")
|
@@ -516,11 +627,6 @@ module ActiveRecord
|
|
516
627
|
end
|
517
628
|
alias :remove_belongs_to :remove_reference
|
518
629
|
|
519
|
-
# Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
|
520
|
-
# entire structure of the database.
|
521
|
-
def structure_dump
|
522
|
-
end
|
523
|
-
|
524
630
|
def dump_schema_information #:nodoc:
|
525
631
|
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
526
632
|
|
@@ -594,27 +700,33 @@ module ActiveRecord
|
|
594
700
|
if options[:null] == false
|
595
701
|
sql << " NOT NULL"
|
596
702
|
end
|
703
|
+
if options[:auto_increment] == true
|
704
|
+
sql << " AUTO_INCREMENT"
|
705
|
+
end
|
597
706
|
end
|
598
707
|
|
599
708
|
# SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
|
600
709
|
# Both PostgreSQL and Oracle overrides this for custom DISTINCT syntax.
|
601
710
|
#
|
602
711
|
# distinct("posts.id", "posts.created_at desc")
|
712
|
+
#
|
603
713
|
def distinct(columns, order_by)
|
604
714
|
"DISTINCT #{columns}"
|
605
715
|
end
|
606
716
|
|
607
|
-
# Adds timestamps (created_at and updated_at) columns to the named table.
|
717
|
+
# Adds timestamps (+created_at+ and +updated_at+) columns to the named table.
|
718
|
+
#
|
719
|
+
# add_timestamps(:suppliers)
|
608
720
|
#
|
609
|
-
# add_timestamps(:suppliers)
|
610
721
|
def add_timestamps(table_name)
|
611
722
|
add_column table_name, :created_at, :datetime
|
612
723
|
add_column table_name, :updated_at, :datetime
|
613
724
|
end
|
614
725
|
|
615
|
-
# Removes the timestamp columns (created_at and updated_at) from the table definition.
|
726
|
+
# Removes the timestamp columns (+created_at+ and +updated_at+) from the table definition.
|
616
727
|
#
|
617
728
|
# remove_timestamps(:suppliers)
|
729
|
+
#
|
618
730
|
def remove_timestamps(table_name)
|
619
731
|
remove_column table_name, :updated_at
|
620
732
|
remove_column table_name, :created_at
|
@@ -655,12 +767,21 @@ module ActiveRecord
|
|
655
767
|
index_name = index_name(table_name, column: column_names)
|
656
768
|
|
657
769
|
if Hash === options # legacy support, since this param was a string
|
658
|
-
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal)
|
770
|
+
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type)
|
659
771
|
|
660
772
|
index_type = options[:unique] ? "UNIQUE" : ""
|
773
|
+
index_type = options[:type].to_s if options.key?(:type)
|
661
774
|
index_name = options[:name].to_s if options.key?(:name)
|
662
775
|
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
663
776
|
|
777
|
+
if options.key?(:algorithm)
|
778
|
+
algorithm = index_algorithms.fetch(options[:algorithm]) {
|
779
|
+
raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
|
780
|
+
}
|
781
|
+
end
|
782
|
+
|
783
|
+
using = "USING #{options[:using]}" if options[:using].present?
|
784
|
+
|
664
785
|
if supports_partial_index?
|
665
786
|
index_options = options[:where] ? " WHERE #{options[:where]}" : ""
|
666
787
|
end
|
@@ -675,6 +796,7 @@ module ActiveRecord
|
|
675
796
|
|
676
797
|
index_type = options
|
677
798
|
max_index_length = allowed_index_name_length
|
799
|
+
algorithm = using = nil
|
678
800
|
end
|
679
801
|
|
680
802
|
if index_name.length > max_index_length
|
@@ -685,13 +807,21 @@ module ActiveRecord
|
|
685
807
|
end
|
686
808
|
index_columns = quoted_columns_for_index(column_names, options).join(", ")
|
687
809
|
|
688
|
-
[index_name, index_type, index_columns, index_options]
|
810
|
+
[index_name, index_type, index_columns, index_options, algorithm, using]
|
689
811
|
end
|
690
812
|
|
691
813
|
def index_name_for_remove(table_name, options = {})
|
692
814
|
index_name = index_name(table_name, options)
|
693
815
|
|
694
816
|
unless index_name_exists?(table_name, index_name, true)
|
817
|
+
if options.is_a?(Hash) && options.has_key?(:name)
|
818
|
+
options_without_column = options.dup
|
819
|
+
options_without_column.delete :column
|
820
|
+
index_name_without_column = index_name(table_name, options_without_column)
|
821
|
+
|
822
|
+
return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
|
823
|
+
end
|
824
|
+
|
695
825
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
|
696
826
|
end
|
697
827
|
|
@@ -727,8 +857,16 @@ module ActiveRecord
|
|
727
857
|
end
|
728
858
|
|
729
859
|
private
|
730
|
-
def
|
731
|
-
TableDefinition.new
|
860
|
+
def create_table_definition(name, temporary, options)
|
861
|
+
TableDefinition.new native_database_types, name, temporary, options
|
862
|
+
end
|
863
|
+
|
864
|
+
def create_alter_table(name)
|
865
|
+
AlterTable.new create_table_definition(name, false, {})
|
866
|
+
end
|
867
|
+
|
868
|
+
def update_table_definition(table_name, base)
|
869
|
+
Table.new(table_name, base)
|
732
870
|
end
|
733
871
|
end
|
734
872
|
end
|