activerecord 3.2.22.5 → 4.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 +4 -4
- data/CHANGELOG.md +1024 -543
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -29
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +55 -44
- data/lib/active_record/aggregations.rb +40 -34
- data/lib/active_record/associations.rb +204 -276
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +30 -35
- data/lib/active_record/associations/association_scope.rb +40 -40
- data/lib/active_record/associations/belongs_to_association.rb +15 -2
- data/lib/active_record/associations/builder/association.rb +81 -28
- data/lib/active_record/associations/builder/belongs_to.rb +35 -57
- data/lib/active_record/associations/builder/collection_association.rb +54 -40
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +13 -50
- data/lib/active_record/associations/builder/singular_association.rb +13 -13
- data/lib/active_record/associations/collection_association.rb +92 -88
- data/lib/active_record/associations/collection_proxy.rb +913 -63
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +12 -10
- data/lib/active_record/associations/has_many_association.rb +35 -9
- data/lib/active_record/associations/has_many_through_association.rb +24 -14
- data/lib/active_record/associations/has_one_association.rb +33 -13
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_helper.rb +1 -11
- data/lib/active_record/associations/preloader.rb +14 -17
- data/lib/active_record/associations/preloader/association.rb +29 -33
- data/lib/active_record/associations/preloader/collection_association.rb +1 -1
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/through_association.rb +13 -17
- data/lib/active_record/associations/singular_association.rb +11 -11
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/attribute_assignment.rb +133 -153
- data/lib/active_record/attribute_methods.rb +196 -93
- data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
- data/lib/active_record/attribute_methods/dirty.rb +31 -28
- data/lib/active_record/attribute_methods/primary_key.rb +38 -30
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +62 -91
- data/lib/active_record/attribute_methods/serialization.rb +97 -66
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -45
- data/lib/active_record/attribute_methods/write.rb +32 -39
- data/lib/active_record/autosave_association.rb +56 -70
- data/lib/active_record/base.rb +53 -450
- data/lib/active_record/callbacks.rb +53 -18
- data/lib/active_record/coders/yaml_column.rb +11 -9
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +353 -197
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -131
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -3
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +101 -91
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +225 -96
- data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +99 -46
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +114 -36
- data/lib/active_record/connection_adapters/column.rb +46 -24
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +181 -64
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +132 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +347 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +158 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +448 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +454 -885
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +574 -13
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +428 -0
- data/lib/active_record/counter_cache.rb +106 -108
- data/lib/active_record/dynamic_matchers.rb +110 -63
- data/lib/active_record/errors.rb +25 -8
- data/lib/active_record/explain.rb +8 -58
- data/lib/active_record/explain_subscriber.rb +6 -3
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +146 -148
- data/lib/active_record/inheritance.rb +77 -59
- data/lib/active_record/integration.rb +5 -5
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +38 -42
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/log_subscriber.rb +19 -9
- data/lib/active_record/migration.rb +318 -153
- data/lib/active_record/migration/command_recorder.rb +90 -31
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/model_schema.rb +69 -92
- data/lib/active_record/nested_attributes.rb +113 -148
- data/lib/active_record/null_relation.rb +65 -0
- data/lib/active_record/persistence.rb +188 -97
- data/lib/active_record/query_cache.rb +18 -36
- data/lib/active_record/querying.rb +19 -15
- data/lib/active_record/railtie.rb +91 -36
- data/lib/active_record/railties/console_sandbox.rb +0 -2
- data/lib/active_record/railties/controller_runtime.rb +2 -2
- data/lib/active_record/railties/databases.rake +90 -309
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +7 -3
- data/lib/active_record/reflection.rb +72 -56
- data/lib/active_record/relation.rb +241 -157
- data/lib/active_record/relation/batches.rb +25 -22
- data/lib/active_record/relation/calculations.rb +143 -121
- data/lib/active_record/relation/delegation.rb +96 -18
- data/lib/active_record/relation/finder_methods.rb +117 -183
- data/lib/active_record/relation/merger.rb +133 -0
- data/lib/active_record/relation/predicate_builder.rb +90 -42
- data/lib/active_record/relation/query_methods.rb +666 -136
- data/lib/active_record/relation/spawn_methods.rb +43 -150
- data/lib/active_record/result.rb +33 -6
- data/lib/active_record/sanitization.rb +24 -50
- data/lib/active_record/schema.rb +19 -12
- data/lib/active_record/schema_dumper.rb +31 -39
- data/lib/active_record/schema_migration.rb +36 -0
- data/lib/active_record/scoping.rb +0 -124
- data/lib/active_record/scoping/default.rb +48 -45
- data/lib/active_record/scoping/named.rb +74 -103
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +9 -15
- data/lib/active_record/store.rb +119 -15
- data/lib/active_record/tasks/database_tasks.rb +158 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +138 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
- data/lib/active_record/test_case.rb +61 -38
- data/lib/active_record/timestamp.rb +8 -9
- data/lib/active_record/transactions.rb +65 -51
- data/lib/active_record/validations.rb +17 -15
- data/lib/active_record/validations/associated.rb +20 -14
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +93 -52
- data/lib/active_record/version.rb +4 -4
- data/lib/rails/generators/active_record.rb +3 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -7
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -3
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- metadata +53 -46
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -360
- data/lib/rails/generators/active_record/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,9 +1,10 @@
|
|
1
|
-
require '
|
2
|
-
require 'active_support/deprecation/reporting'
|
1
|
+
require 'active_record/migration/join_table'
|
3
2
|
|
4
3
|
module ActiveRecord
|
5
4
|
module ConnectionAdapters # :nodoc:
|
6
5
|
module SchemaStatements
|
6
|
+
include ActiveRecord::Migration::JoinTable
|
7
|
+
|
7
8
|
# Returns a Hash of mappings from the abstract data types to the native
|
8
9
|
# database types. See TableDefinition#column for details on the recognized
|
9
10
|
# abstract data types.
|
@@ -13,12 +14,11 @@ module ActiveRecord
|
|
13
14
|
|
14
15
|
# Truncates a table alias according to the limits of the current adapter.
|
15
16
|
def table_alias_for(table_name)
|
16
|
-
table_name[0...table_alias_length].
|
17
|
+
table_name[0...table_alias_length].tr('.', '_')
|
17
18
|
end
|
18
19
|
|
19
20
|
# Checks to see if the table +table_name+ exists on the database.
|
20
21
|
#
|
21
|
-
# === Example
|
22
22
|
# table_exists?(:developers)
|
23
23
|
def table_exists?(table_name)
|
24
24
|
tables.include?(table_name.to_s)
|
@@ -29,7 +29,6 @@ module ActiveRecord
|
|
29
29
|
|
30
30
|
# Checks to see if an index exists on a table for a given index definition.
|
31
31
|
#
|
32
|
-
# === Examples
|
33
32
|
# # Check an index exists
|
34
33
|
# index_exists?(:suppliers, :company_id)
|
35
34
|
#
|
@@ -37,12 +36,12 @@ module ActiveRecord
|
|
37
36
|
# index_exists?(:suppliers, [:company_id, :company_type])
|
38
37
|
#
|
39
38
|
# # Check a unique index exists
|
40
|
-
# index_exists?(:suppliers, :company_id, :
|
39
|
+
# index_exists?(:suppliers, :company_id, unique: true)
|
41
40
|
#
|
42
41
|
# # Check an index with a custom name exists
|
43
|
-
# index_exists?(:suppliers, :company_id, :
|
42
|
+
# index_exists?(:suppliers, :company_id, name: "idx_company_id"
|
44
43
|
def index_exists?(table_name, column_name, options = {})
|
45
|
-
column_names = Array
|
44
|
+
column_names = Array(column_name)
|
46
45
|
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, :column => column_names)
|
47
46
|
if options[:unique]
|
48
47
|
indexes(table_name).any?{ |i| i.unique && i.name == index_name }
|
@@ -53,11 +52,10 @@ module ActiveRecord
|
|
53
52
|
|
54
53
|
# Returns an array of Column objects for the table specified by +table_name+.
|
55
54
|
# See the concrete implementation for details on the expected parameter values.
|
56
|
-
def columns(table_name
|
55
|
+
def columns(table_name) end
|
57
56
|
|
58
57
|
# Checks to see if a column exists in a given table.
|
59
58
|
#
|
60
|
-
# === Examples
|
61
59
|
# # Check a column exists
|
62
60
|
# column_exists?(:suppliers, :name)
|
63
61
|
#
|
@@ -65,13 +63,18 @@ module ActiveRecord
|
|
65
63
|
# column_exists?(:suppliers, :name, :string)
|
66
64
|
#
|
67
65
|
# # Check a column exists with a specific definition
|
68
|
-
# column_exists?(:suppliers, :name, :string, :
|
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)
|
69
70
|
def column_exists?(table_name, column_name, type = nil, options = {})
|
70
71
|
columns(table_name).any?{ |c| c.name == column_name.to_s &&
|
71
|
-
(!type
|
72
|
-
(!options
|
73
|
-
(!options
|
74
|
-
(!options
|
72
|
+
(!type || c.type == type) &&
|
73
|
+
(!options.key?(:limit) || c.limit == options[:limit]) &&
|
74
|
+
(!options.key?(:precision) || c.precision == options[:precision]) &&
|
75
|
+
(!options.key?(:scale) || c.scale == options[:scale]) &&
|
76
|
+
(!options.key?(:default) || c.default == options[:default]) &&
|
77
|
+
(!options.key?(:null) || c.null == options[:null]) }
|
75
78
|
end
|
76
79
|
|
77
80
|
# Creates a new table with the name +table_name+. +table_name+ may either
|
@@ -86,14 +89,14 @@ module ActiveRecord
|
|
86
89
|
# # table.
|
87
90
|
#
|
88
91
|
# create_table(:suppliers) do |t|
|
89
|
-
# t.column :name, :string, :
|
92
|
+
# t.column :name, :string, limit: 60
|
90
93
|
# # Other fields here
|
91
94
|
# end
|
92
95
|
#
|
93
96
|
# === Block form, with shorthand
|
94
97
|
# # You can also use the column types as method calls, rather than calling the column method.
|
95
98
|
# create_table(:suppliers) do |t|
|
96
|
-
# t.string :name, :
|
99
|
+
# t.string :name, limit: 60
|
97
100
|
# # Other fields here
|
98
101
|
# end
|
99
102
|
#
|
@@ -101,7 +104,7 @@ module ActiveRecord
|
|
101
104
|
# # Creates a table called 'suppliers' with no columns.
|
102
105
|
# create_table(:suppliers)
|
103
106
|
# # Add a column to 'suppliers'.
|
104
|
-
# add_column(:suppliers, :name, :string, {:
|
107
|
+
# add_column(:suppliers, :name, :string, {limit: 60})
|
105
108
|
#
|
106
109
|
# The +options+ hash can include the following keys:
|
107
110
|
# [<tt>:id</tt>]
|
@@ -123,17 +126,16 @@ module ActiveRecord
|
|
123
126
|
# Set to true to drop the table before creating it.
|
124
127
|
# Defaults to false.
|
125
128
|
#
|
126
|
-
# ===== Examples
|
127
129
|
# ====== Add a backend specific option to the generated SQL (MySQL)
|
128
|
-
# create_table(:suppliers, :
|
130
|
+
# create_table(:suppliers, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
|
129
131
|
# generates:
|
130
132
|
# CREATE TABLE suppliers (
|
131
133
|
# id int(11) DEFAULT NULL auto_increment PRIMARY KEY
|
132
134
|
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
133
135
|
#
|
134
136
|
# ====== Rename the primary key column
|
135
|
-
# create_table(:objects, :
|
136
|
-
# t.column :name, :string, :
|
137
|
+
# create_table(:objects, primary_key: 'guid') do |t|
|
138
|
+
# t.column :name, :string, limit: 80
|
137
139
|
# end
|
138
140
|
# generates:
|
139
141
|
# CREATE TABLE objects (
|
@@ -142,7 +144,7 @@ module ActiveRecord
|
|
142
144
|
# )
|
143
145
|
#
|
144
146
|
# ====== Do not add a primary key column
|
145
|
-
# create_table(:categories_suppliers, :
|
147
|
+
# create_table(:categories_suppliers, id: false) do |t|
|
146
148
|
# t.column :category_id, :integer
|
147
149
|
# t.column :supplier_id, :integer
|
148
150
|
# end
|
@@ -168,14 +170,74 @@ module ActiveRecord
|
|
168
170
|
create_sql << td.to_sql
|
169
171
|
create_sql << ") #{options[:options]}"
|
170
172
|
execute create_sql
|
173
|
+
td.indexes.each_pair { |c,o| add_index table_name, c, o }
|
174
|
+
end
|
175
|
+
|
176
|
+
# Creates a new join table with the name created using the lexical order of the first two
|
177
|
+
# arguments. These arguments can be a String or a Symbol.
|
178
|
+
#
|
179
|
+
# # Creates a table called 'assemblies_parts' with no id.
|
180
|
+
# create_join_table(:assemblies, :parts)
|
181
|
+
#
|
182
|
+
# You can pass a +options+ hash can include the following keys:
|
183
|
+
# [<tt>:table_name</tt>]
|
184
|
+
# Sets the table name overriding the default
|
185
|
+
# [<tt>:column_options</tt>]
|
186
|
+
# Any extra options you want appended to the columns definition.
|
187
|
+
# [<tt>:options</tt>]
|
188
|
+
# Any extra options you want appended to the table definition.
|
189
|
+
# [<tt>:temporary</tt>]
|
190
|
+
# Make a temporary table.
|
191
|
+
# [<tt>:force</tt>]
|
192
|
+
# Set to true to drop the table before creating it.
|
193
|
+
# Defaults to false.
|
194
|
+
#
|
195
|
+
# Note that +create_join_table+ does not create any indices by default; you can use
|
196
|
+
# its block form to do so yourself:
|
197
|
+
#
|
198
|
+
# create_join_table :products, :categories do |t|
|
199
|
+
# t.index :products
|
200
|
+
# t.index :categories
|
201
|
+
# end
|
202
|
+
#
|
203
|
+
# ====== Add a backend specific option to the generated SQL (MySQL)
|
204
|
+
# create_join_table(:assemblies, :parts, options: 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
|
205
|
+
# generates:
|
206
|
+
# CREATE TABLE assemblies_parts (
|
207
|
+
# assembly_id int NOT NULL,
|
208
|
+
# part_id int NOT NULL,
|
209
|
+
# ) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
210
|
+
def create_join_table(table_1, table_2, options = {})
|
211
|
+
join_table_name = find_join_table_name(table_1, table_2, options)
|
212
|
+
|
213
|
+
column_options = options.delete(:column_options) || {}
|
214
|
+
column_options.reverse_merge!(null: false)
|
215
|
+
|
216
|
+
t1_column, t2_column = [table_1, table_2].map{ |t| t.to_s.singularize.foreign_key }
|
217
|
+
|
218
|
+
create_table(join_table_name, options.merge!(id: false)) do |td|
|
219
|
+
td.integer t1_column, column_options
|
220
|
+
td.integer t2_column, column_options
|
221
|
+
yield td if block_given?
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Drops the join table specified by the given arguments.
|
226
|
+
# See create_join_table for details.
|
227
|
+
#
|
228
|
+
# Although this command ignores the block if one is given, it can be helpful
|
229
|
+
# to provide one in a migration's +change+ method so it can be reverted.
|
230
|
+
# In that case, the block will be used by create_join_table.
|
231
|
+
def drop_join_table(table_1, table_2, options = {})
|
232
|
+
join_table_name = find_join_table_name(table_1, table_2, options)
|
233
|
+
drop_table(join_table_name)
|
171
234
|
end
|
172
235
|
|
173
236
|
# A block for changing columns in +table+.
|
174
237
|
#
|
175
|
-
# === Example
|
176
238
|
# # change_table() yields a Table instance
|
177
239
|
# change_table(:suppliers) do |t|
|
178
|
-
# t.column :name, :string, :
|
240
|
+
# t.column :name, :string, limit: 60
|
179
241
|
# # Other column alterations here
|
180
242
|
# end
|
181
243
|
#
|
@@ -186,15 +248,14 @@ module ActiveRecord
|
|
186
248
|
#
|
187
249
|
# Defaults to false.
|
188
250
|
#
|
189
|
-
# ===== Examples
|
190
251
|
# ====== Add a column
|
191
252
|
# change_table(:suppliers) do |t|
|
192
|
-
# t.column :name, :string, :
|
253
|
+
# t.column :name, :string, limit: 60
|
193
254
|
# end
|
194
255
|
#
|
195
256
|
# ====== Add 2 integer columns
|
196
257
|
# change_table(:suppliers) do |t|
|
197
|
-
# t.integer :width, :height, :
|
258
|
+
# t.integer :width, :height, null: false, default: 0
|
198
259
|
# end
|
199
260
|
#
|
200
261
|
# ====== Add created_at/updated_at columns
|
@@ -211,7 +272,7 @@ module ActiveRecord
|
|
211
272
|
#
|
212
273
|
# ====== Add a polymorphic foreign key column
|
213
274
|
# change_table(:suppliers) do |t|
|
214
|
-
# t.belongs_to :company, :
|
275
|
+
# t.belongs_to :company, polymorphic: true
|
215
276
|
# end
|
216
277
|
#
|
217
278
|
# Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns
|
@@ -245,13 +306,17 @@ module ActiveRecord
|
|
245
306
|
end
|
246
307
|
|
247
308
|
# Renames a table.
|
248
|
-
#
|
309
|
+
#
|
249
310
|
# rename_table('octopuses', 'octopi')
|
250
311
|
def rename_table(table_name, new_name)
|
251
312
|
raise NotImplementedError, "rename_table is not implemented"
|
252
313
|
end
|
253
314
|
|
254
315
|
# Drops a table from the database.
|
316
|
+
#
|
317
|
+
# Although this command ignores +options+ and the block if one is given, it can be helpful
|
318
|
+
# to provide these in a migration's +change+ method so it can be reverted.
|
319
|
+
# In that case, +options+ and the block will be used by create_table.
|
255
320
|
def drop_table(table_name, options = {})
|
256
321
|
execute "DROP TABLE #{quote_table_name(table_name)}"
|
257
322
|
end
|
@@ -264,34 +329,38 @@ module ActiveRecord
|
|
264
329
|
execute(add_column_sql)
|
265
330
|
end
|
266
331
|
|
267
|
-
# Removes the
|
268
|
-
#
|
269
|
-
# remove_column(:suppliers, :qualification)
|
332
|
+
# Removes the given columns from the table definition.
|
333
|
+
#
|
270
334
|
# remove_columns(:suppliers, :qualification, :experience)
|
271
|
-
def
|
272
|
-
if column_names.
|
273
|
-
|
274
|
-
|
275
|
-
ActiveSupport::Deprecation.warn message, caller
|
335
|
+
def remove_columns(table_name, *column_names)
|
336
|
+
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)") if column_names.empty?
|
337
|
+
column_names.each do |column_name|
|
338
|
+
remove_column(table_name, column_name)
|
276
339
|
end
|
340
|
+
end
|
277
341
|
|
278
|
-
|
279
|
-
|
280
|
-
|
342
|
+
# Removes the column from the table definition.
|
343
|
+
#
|
344
|
+
# remove_column(:suppliers, :qualification)
|
345
|
+
#
|
346
|
+
# The +type+ and +options+ parameters will be ignored if present. It can be helpful
|
347
|
+
# to provide these in a migration's +change+ method so it can be reverted.
|
348
|
+
# In that case, +type+ and +options+ will be used by add_column.
|
349
|
+
def remove_column(table_name, column_name, type = nil, options = {})
|
350
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
|
281
351
|
end
|
282
|
-
alias :remove_columns :remove_column
|
283
352
|
|
284
353
|
# Changes the column's definition according to the new options.
|
285
354
|
# See TableDefinition#column for details of the options you can use.
|
286
|
-
#
|
287
|
-
# change_column(:suppliers, :name, :string, :
|
355
|
+
#
|
356
|
+
# change_column(:suppliers, :name, :string, limit: 80)
|
288
357
|
# change_column(:accounts, :description, :text)
|
289
358
|
def change_column(table_name, column_name, type, options = {})
|
290
359
|
raise NotImplementedError, "change_column is not implemented"
|
291
360
|
end
|
292
361
|
|
293
362
|
# Sets a new default value for a column.
|
294
|
-
#
|
363
|
+
#
|
295
364
|
# change_column_default(:suppliers, :qualification, 'new')
|
296
365
|
# change_column_default(:accounts, :authorized, 1)
|
297
366
|
# change_column_default(:users, :email, nil)
|
@@ -300,7 +369,7 @@ module ActiveRecord
|
|
300
369
|
end
|
301
370
|
|
302
371
|
# Renames a column.
|
303
|
-
#
|
372
|
+
#
|
304
373
|
# rename_column(:suppliers, :description, :name)
|
305
374
|
def rename_column(table_name, column_name, new_column_name)
|
306
375
|
raise NotImplementedError, "rename_column is not implemented"
|
@@ -312,44 +381,49 @@ module ActiveRecord
|
|
312
381
|
# The index will be named after the table and the column name(s), unless
|
313
382
|
# you pass <tt>:name</tt> as an option.
|
314
383
|
#
|
315
|
-
# ===== Examples
|
316
|
-
#
|
317
384
|
# ====== Creating a simple index
|
318
385
|
# add_index(:suppliers, :name)
|
319
386
|
# generates
|
320
387
|
# CREATE INDEX suppliers_name_index ON suppliers(name)
|
321
388
|
#
|
322
389
|
# ====== Creating a unique index
|
323
|
-
# add_index(:accounts, [:branch_id, :party_id], :
|
390
|
+
# add_index(:accounts, [:branch_id, :party_id], unique: true)
|
324
391
|
# generates
|
325
392
|
# CREATE UNIQUE INDEX accounts_branch_id_party_id_index ON accounts(branch_id, party_id)
|
326
393
|
#
|
327
394
|
# ====== Creating a named index
|
328
|
-
# add_index(:accounts, [:branch_id, :party_id], :
|
395
|
+
# add_index(:accounts, [:branch_id, :party_id], unique: true, name: 'by_branch_party')
|
329
396
|
# generates
|
330
397
|
# CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id)
|
331
398
|
#
|
332
399
|
# ====== Creating an index with specific key length
|
333
|
-
# add_index(:accounts, :name, :
|
400
|
+
# add_index(:accounts, :name, name: 'by_name', length: 10)
|
334
401
|
# generates
|
335
402
|
# CREATE INDEX by_name ON accounts(name(10))
|
336
403
|
#
|
337
|
-
# add_index(:accounts, [:name, :surname], :
|
404
|
+
# add_index(:accounts, [:name, :surname], name: 'by_name_surname', length: {name: 10, surname: 15})
|
338
405
|
# generates
|
339
406
|
# CREATE INDEX by_name_surname ON accounts(name(10), surname(15))
|
340
407
|
#
|
341
408
|
# Note: SQLite doesn't support index length
|
342
409
|
#
|
343
410
|
# ====== Creating an index with a sort order (desc or asc, asc is the default)
|
344
|
-
# add_index(:accounts, [:branch_id, :party_id, :surname], :
|
411
|
+
# add_index(:accounts, [:branch_id, :party_id, :surname], order: {branch_id: :desc, party_id: :asc})
|
345
412
|
# generates
|
346
413
|
# CREATE INDEX by_branch_desc_party ON accounts(branch_id DESC, party_id ASC, surname)
|
347
414
|
#
|
348
415
|
# Note: mysql doesn't yet support index order (it accepts the syntax but ignores it)
|
349
416
|
#
|
417
|
+
# ====== 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
|
+
#
|
422
|
+
# Note: only supported by PostgreSQL
|
423
|
+
#
|
350
424
|
def add_index(table_name, column_name, options = {})
|
351
|
-
index_name, index_type, index_columns = add_index_options(table_name, column_name, options)
|
352
|
-
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})"
|
425
|
+
index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
|
426
|
+
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
|
353
427
|
end
|
354
428
|
|
355
429
|
# Remove the given index from the table.
|
@@ -357,11 +431,11 @@ module ActiveRecord
|
|
357
431
|
# Remove the index_accounts_on_column in the accounts table.
|
358
432
|
# remove_index :accounts, :column
|
359
433
|
# Remove the index named index_accounts_on_branch_id in the accounts table.
|
360
|
-
# remove_index :accounts, :
|
434
|
+
# remove_index :accounts, column: :branch_id
|
361
435
|
# Remove the index named index_accounts_on_branch_id_and_party_id in the accounts table.
|
362
|
-
# remove_index :accounts, :
|
436
|
+
# remove_index :accounts, column: [:branch_id, :party_id]
|
363
437
|
# Remove the index named by_branch_party in the accounts table.
|
364
|
-
# remove_index :accounts, :
|
438
|
+
# remove_index :accounts, name: :by_branch_party
|
365
439
|
def remove_index(table_name, options = {})
|
366
440
|
remove_index!(table_name, index_name_for_remove(table_name, options))
|
367
441
|
end
|
@@ -383,9 +457,9 @@ module ActiveRecord
|
|
383
457
|
end
|
384
458
|
|
385
459
|
def index_name(table_name, options) #:nodoc:
|
386
|
-
if Hash === options
|
460
|
+
if Hash === options
|
387
461
|
if options[:column]
|
388
|
-
"index_#{table_name}_on_#{Array
|
462
|
+
"index_#{table_name}_on_#{Array(options[:column]) * '_and_'}"
|
389
463
|
elsif options[:name]
|
390
464
|
options[:name]
|
391
465
|
else
|
@@ -406,6 +480,42 @@ module ActiveRecord
|
|
406
480
|
indexes(table_name).detect { |i| i.name == index_name }
|
407
481
|
end
|
408
482
|
|
483
|
+
# Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
|
484
|
+
# <tt>add_reference</tt> and <tt>add_belongs_to</tt> are acceptable.
|
485
|
+
#
|
486
|
+
# ====== Create a user_id column
|
487
|
+
# add_reference(:products, :user)
|
488
|
+
#
|
489
|
+
# ====== Create a supplier_id and supplier_type columns
|
490
|
+
# add_belongs_to(:products, :supplier, polymorphic: true)
|
491
|
+
#
|
492
|
+
# ====== Create a supplier_id, supplier_type columns and appropriate index
|
493
|
+
# add_reference(:products, :supplier, polymorphic: true, index: true)
|
494
|
+
#
|
495
|
+
def add_reference(table_name, ref_name, options = {})
|
496
|
+
polymorphic = options.delete(:polymorphic)
|
497
|
+
index_options = options.delete(:index)
|
498
|
+
add_column(table_name, "#{ref_name}_id", :integer, options)
|
499
|
+
add_column(table_name, "#{ref_name}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
|
500
|
+
add_index(table_name, polymorphic ? %w[id type].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : nil) if index_options
|
501
|
+
end
|
502
|
+
alias :add_belongs_to :add_reference
|
503
|
+
|
504
|
+
# Removes the reference(s). Also removes a +type+ column if one exists.
|
505
|
+
# <tt>remove_reference</tt>, <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
|
506
|
+
#
|
507
|
+
# ====== Remove the reference
|
508
|
+
# remove_reference(:products, :user, index: true)
|
509
|
+
#
|
510
|
+
# ====== Remove polymorphic reference
|
511
|
+
# remove_reference(:products, :supplier, polymorphic: true)
|
512
|
+
#
|
513
|
+
def remove_reference(table_name, ref_name, options = {})
|
514
|
+
remove_column(table_name, "#{ref_name}_id")
|
515
|
+
remove_column(table_name, "#{ref_name}_type") if options[:polymorphic]
|
516
|
+
end
|
517
|
+
alias :remove_belongs_to :remove_reference
|
518
|
+
|
409
519
|
# Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the
|
410
520
|
# entire structure of the database.
|
411
521
|
def structure_dump
|
@@ -413,38 +523,20 @@ module ActiveRecord
|
|
413
523
|
|
414
524
|
def dump_schema_information #:nodoc:
|
415
525
|
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
416
|
-
|
417
|
-
|
526
|
+
|
527
|
+
ActiveRecord::SchemaMigration.order('version').map { |sm|
|
528
|
+
"INSERT INTO #{sm_table} (version) VALUES ('#{sm.version}');"
|
529
|
+
}.join "\n\n"
|
418
530
|
end
|
419
531
|
|
420
532
|
# Should not be called normally, but this operation is non-destructive.
|
421
533
|
# The migrations module handles this automatically.
|
422
534
|
def initialize_schema_migrations_table
|
423
|
-
|
424
|
-
|
425
|
-
unless table_exists?(sm_table)
|
426
|
-
create_table(sm_table, :id => false) do |schema_migrations_table|
|
427
|
-
schema_migrations_table.column :version, :string, :null => false
|
428
|
-
end
|
429
|
-
add_index sm_table, :version, :unique => true,
|
430
|
-
:name => "#{Base.table_name_prefix}unique_schema_migrations#{Base.table_name_suffix}"
|
431
|
-
|
432
|
-
# Backwards-compatibility: if we find schema_info, assume we've
|
433
|
-
# migrated up to that point:
|
434
|
-
si_table = Base.table_name_prefix + 'schema_info' + Base.table_name_suffix
|
435
|
-
|
436
|
-
if table_exists?(si_table)
|
437
|
-
ActiveSupport::Deprecation.warn "Usage of the schema table `#{si_table}` is deprecated. Please switch to using `schema_migrations` table"
|
438
|
-
|
439
|
-
old_version = select_value("SELECT version FROM #{quote_table_name(si_table)}").to_i
|
440
|
-
assume_migrated_upto_version(old_version)
|
441
|
-
drop_table(si_table)
|
442
|
-
end
|
443
|
-
end
|
535
|
+
ActiveRecord::SchemaMigration.create_table
|
444
536
|
end
|
445
537
|
|
446
538
|
def assume_migrated_upto_version(version, migrations_paths = ActiveRecord::Migrator.migrations_paths)
|
447
|
-
migrations_paths = Array
|
539
|
+
migrations_paths = Array(migrations_paths)
|
448
540
|
version = version.to_i
|
449
541
|
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
|
450
542
|
|
@@ -483,7 +575,7 @@ module ActiveRecord
|
|
483
575
|
column_type_sql << "(#{precision})"
|
484
576
|
end
|
485
577
|
elsif scale
|
486
|
-
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale
|
578
|
+
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
|
487
579
|
end
|
488
580
|
|
489
581
|
elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
|
@@ -513,7 +605,7 @@ module ActiveRecord
|
|
513
605
|
end
|
514
606
|
|
515
607
|
# Adds timestamps (created_at and updated_at) columns to the named table.
|
516
|
-
#
|
608
|
+
#
|
517
609
|
# add_timestamps(:suppliers)
|
518
610
|
def add_timestamps(table_name)
|
519
611
|
add_column table_name, :created_at, :datetime
|
@@ -521,7 +613,7 @@ module ActiveRecord
|
|
521
613
|
end
|
522
614
|
|
523
615
|
# Removes the timestamp columns (created_at and updated_at) from the table definition.
|
524
|
-
#
|
616
|
+
#
|
525
617
|
# remove_timestamps(:suppliers)
|
526
618
|
def remove_timestamps(table_name)
|
527
619
|
remove_column table_name, :updated_at
|
@@ -533,7 +625,7 @@ module ActiveRecord
|
|
533
625
|
if options.is_a?(Hash) && order = options[:order]
|
534
626
|
case order
|
535
627
|
when Hash
|
536
|
-
column_names.each {|name| option_strings[name] += " #{order[name].
|
628
|
+
column_names.each {|name| option_strings[name] += " #{order[name].upcase}" if order.has_key?(name)}
|
537
629
|
when String
|
538
630
|
column_names.each {|name| option_strings[name] += " #{order.upcase}"}
|
539
631
|
end
|
@@ -559,25 +651,41 @@ module ActiveRecord
|
|
559
651
|
end
|
560
652
|
|
561
653
|
def add_index_options(table_name, column_name, options = {})
|
562
|
-
column_names = Array
|
563
|
-
index_name = index_name(table_name, :
|
654
|
+
column_names = Array(column_name)
|
655
|
+
index_name = index_name(table_name, column: column_names)
|
564
656
|
|
565
657
|
if Hash === options # legacy support, since this param was a string
|
658
|
+
options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal)
|
659
|
+
|
566
660
|
index_type = options[:unique] ? "UNIQUE" : ""
|
567
661
|
index_name = options[:name].to_s if options.key?(:name)
|
662
|
+
max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
|
663
|
+
|
664
|
+
if supports_partial_index?
|
665
|
+
index_options = options[:where] ? " WHERE #{options[:where]}" : ""
|
666
|
+
end
|
568
667
|
else
|
668
|
+
if options
|
669
|
+
message = "Passing a string as third argument of `add_index` is deprecated and will" +
|
670
|
+
" be removed in Rails 4.1." +
|
671
|
+
" Use add_index(#{table_name.inspect}, #{column_name.inspect}, unique: true) instead"
|
672
|
+
|
673
|
+
ActiveSupport::Deprecation.warn message
|
674
|
+
end
|
675
|
+
|
569
676
|
index_type = options
|
677
|
+
max_index_length = allowed_index_name_length
|
570
678
|
end
|
571
679
|
|
572
|
-
if index_name.length >
|
573
|
-
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{
|
680
|
+
if index_name.length > max_index_length
|
681
|
+
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
|
574
682
|
end
|
575
683
|
if index_name_exists?(table_name, index_name, false)
|
576
684
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
577
685
|
end
|
578
686
|
index_columns = quoted_columns_for_index(column_names, options).join(", ")
|
579
687
|
|
580
|
-
[index_name, index_type, index_columns]
|
688
|
+
[index_name, index_type, index_columns, index_options]
|
581
689
|
end
|
582
690
|
|
583
691
|
def index_name_for_remove(table_name, options = {})
|
@@ -591,12 +699,33 @@ module ActiveRecord
|
|
591
699
|
end
|
592
700
|
|
593
701
|
def columns_for_remove(table_name, *column_names)
|
594
|
-
|
595
|
-
|
596
|
-
raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.blank?
|
702
|
+
ActiveSupport::Deprecation.warn("columns_for_remove is deprecated and will be removed in the future")
|
703
|
+
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)") if column_names.blank?
|
597
704
|
column_names.map {|column_name| quote_column_name(column_name) }
|
598
705
|
end
|
599
706
|
|
707
|
+
def rename_table_indexes(table_name, new_name)
|
708
|
+
indexes(new_name).each do |index|
|
709
|
+
generated_index_name = index_name(table_name, column: index.columns)
|
710
|
+
if generated_index_name == index.name
|
711
|
+
rename_index new_name, generated_index_name, index_name(new_name, column: index.columns)
|
712
|
+
end
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
def rename_column_indexes(table_name, column_name, new_column_name)
|
717
|
+
column_name, new_column_name = column_name.to_s, new_column_name.to_s
|
718
|
+
indexes(table_name).each do |index|
|
719
|
+
next unless index.columns.include?(new_column_name)
|
720
|
+
old_columns = index.columns.dup
|
721
|
+
old_columns[old_columns.index(new_column_name)] = column_name
|
722
|
+
generated_index_name = index_name(table_name, column: old_columns)
|
723
|
+
if generated_index_name == index.name
|
724
|
+
rename_index table_name, generated_index_name, index_name(table_name, column: index.columns)
|
725
|
+
end
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|
600
729
|
private
|
601
730
|
def table_definition
|
602
731
|
TableDefinition.new(self)
|