schema_plus_foreign_keys 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +21 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +200 -0
- data/Rakefile +9 -0
- data/gemfiles/Gemfile.base +4 -0
- data/gemfiles/activerecord-4.2.0/Gemfile.base +3 -0
- data/gemfiles/activerecord-4.2.0/Gemfile.mysql2 +10 -0
- data/gemfiles/activerecord-4.2.0/Gemfile.postgresql +10 -0
- data/gemfiles/activerecord-4.2.0/Gemfile.sqlite3 +10 -0
- data/gemfiles/activerecord-4.2.1/Gemfile.base +3 -0
- data/gemfiles/activerecord-4.2.1/Gemfile.mysql2 +10 -0
- data/gemfiles/activerecord-4.2.1/Gemfile.postgresql +10 -0
- data/gemfiles/activerecord-4.2.1/Gemfile.sqlite3 +10 -0
- data/lib/schema_plus/foreign_keys.rb +78 -0
- data/lib/schema_plus/foreign_keys/active_record/base.rb +33 -0
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/abstract_adapter.rb +168 -0
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/foreign_key_definition.rb +137 -0
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/mysql2_adapter.rb +126 -0
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/postgresql_adapter.rb +89 -0
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/sqlite3_adapter.rb +77 -0
- data/lib/schema_plus/foreign_keys/active_record/connection_adapters/table_definition.rb +108 -0
- data/lib/schema_plus/foreign_keys/active_record/migration/command_recorder.rb +29 -0
- data/lib/schema_plus/foreign_keys/middleware/dumper.rb +88 -0
- data/lib/schema_plus/foreign_keys/middleware/migration.rb +147 -0
- data/lib/schema_plus/foreign_keys/middleware/model.rb +15 -0
- data/lib/schema_plus/foreign_keys/middleware/mysql.rb +20 -0
- data/lib/schema_plus/foreign_keys/middleware/sql.rb +27 -0
- data/lib/schema_plus/foreign_keys/version.rb +5 -0
- data/lib/schema_plus_foreign_keys.rb +1 -0
- data/schema_dev.yml +9 -0
- data/schema_plus_foreign_keys.gemspec +31 -0
- data/spec/deprecation_spec.rb +161 -0
- data/spec/foreign_key_definition_spec.rb +34 -0
- data/spec/foreign_key_spec.rb +207 -0
- data/spec/migration_spec.rb +570 -0
- data/spec/named_schemas_spec.rb +136 -0
- data/spec/schema_dumper_spec.rb +257 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/support/reference.rb +79 -0
- metadata +221 -0
@@ -0,0 +1,570 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe ActiveRecord::Migration do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
define_schema do
|
8
|
+
|
9
|
+
create_table :users, :force => true do |t|
|
10
|
+
t.string :login, :index => { :unique => true }
|
11
|
+
end
|
12
|
+
|
13
|
+
create_table :members, :force => true do |t|
|
14
|
+
t.string :login
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table :comments, :force => true do |t|
|
18
|
+
t.string :content
|
19
|
+
t.integer :user
|
20
|
+
t.integer :user_id
|
21
|
+
t.foreign_key :user_id, :users, :primary_key => :id
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table :posts, :force => true do |t|
|
25
|
+
t.string :content
|
26
|
+
end
|
27
|
+
end
|
28
|
+
class User < ::ActiveRecord::Base ; end
|
29
|
+
class Post < ::ActiveRecord::Base ; end
|
30
|
+
class Comment < ::ActiveRecord::Base ; end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when table is created" do
|
34
|
+
|
35
|
+
before(:each) do
|
36
|
+
@model = Post
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should enable foreign keys", :sqlite3 => :only do
|
40
|
+
sql = []
|
41
|
+
allow(@model.connection).to receive(:execute) { |str| sql << str }
|
42
|
+
recreate_table(@model) do |t|
|
43
|
+
t.integer :user, :foreign_key => true
|
44
|
+
end
|
45
|
+
expect(sql.join('; ')).to match(/PRAGMA FOREIGN_KEYS = ON.*CREATE TABLE "posts"/)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should create foreign key with default reference" do
|
49
|
+
recreate_table(@model) do |t|
|
50
|
+
t.integer :user, :foreign_key => true
|
51
|
+
end
|
52
|
+
expect(@model).to reference(:users, :id).on(:user)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should create foreign key with default column" do
|
56
|
+
recreate_table(@model) do |t|
|
57
|
+
t.integer :user_id
|
58
|
+
t.foreign_key :users
|
59
|
+
end
|
60
|
+
expect(@model).to reference(:users, :id).on(:user_id)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should create foreign key with different reference" do
|
64
|
+
recreate_table(@model) do |t|
|
65
|
+
t.integer :author_id, :foreign_key => { :references => :users }
|
66
|
+
end
|
67
|
+
expect(@model).to reference(:users, :id).on(:author_id)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should create foreign key without modifying input hash" do
|
71
|
+
hash = { :references => :users }
|
72
|
+
hash_original = hash.dup
|
73
|
+
recreate_table(@model) do |t|
|
74
|
+
t.integer :author_id, :foreign_key => hash
|
75
|
+
end
|
76
|
+
expect(hash).to eq(hash_original)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should create foreign key without modifying input hash" do
|
80
|
+
hash = { :references => :users }
|
81
|
+
hash_original = hash.dup
|
82
|
+
recreate_table(@model) do |t|
|
83
|
+
t.references :author, :foreign_key => hash
|
84
|
+
end
|
85
|
+
expect(hash).to eq(hash_original)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should create foreign key with different reference using shortcut" do
|
89
|
+
recreate_table(@model) do |t|
|
90
|
+
t.integer :author_id, :references => :users
|
91
|
+
end
|
92
|
+
expect(@model).to reference(:users, :id).on(:author_id)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should create foreign key with default name" do
|
96
|
+
recreate_table @model do |t|
|
97
|
+
t.integer :user_id, :foreign_key => true
|
98
|
+
end
|
99
|
+
expect(@model).to reference(:users, :id).with_name("fk_#{@model.table_name}_user_id")
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should create foreign key with specified name" do
|
103
|
+
recreate_table @model do |t|
|
104
|
+
t.integer :user_id, :foreign_key => { :name => "wugga" }
|
105
|
+
end
|
106
|
+
expect(@model).to reference(:users, :id).with_name("wugga")
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should allow multiple foreign keys to be made" do
|
110
|
+
recreate_table(@model) do |t|
|
111
|
+
t.integer :user_id, :references => :users
|
112
|
+
t.integer :updater_id, :references => :users
|
113
|
+
end
|
114
|
+
expect(@model).to reference(:users, :id).on(:user_id)
|
115
|
+
expect(@model).to reference(:users, :id).on(:updater_id)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should suppress foreign key" do
|
119
|
+
recreate_table(@model) do |t|
|
120
|
+
t.integer :member_id, :foreign_key => false
|
121
|
+
end
|
122
|
+
expect(@model).not_to reference.on(:member_id)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should suppress foreign key using shortcut" do
|
126
|
+
recreate_table(@model) do |t|
|
127
|
+
t.integer :member_id, :references => nil
|
128
|
+
end
|
129
|
+
expect(@model).not_to reference.on(:member_id)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should create foreign key using t.belongs_to" do
|
133
|
+
recreate_table(@model) do |t|
|
134
|
+
t.belongs_to :user, :foreign_key => true
|
135
|
+
end
|
136
|
+
expect(@model).to reference(:users, :id).on(:user_id)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should not create foreign key using t.belongs_to with :polymorphic => true" do
|
140
|
+
recreate_table(@model) do |t|
|
141
|
+
t.belongs_to :user, :polymorphic => true
|
142
|
+
end
|
143
|
+
expect(@model).not_to reference(:users, :id).on(:user_id)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should create foreign key using t.references" do
|
147
|
+
recreate_table(@model) do |t|
|
148
|
+
t.references :user, :foreign_key => true
|
149
|
+
end
|
150
|
+
expect(@model).to reference(:users, :id).on(:user_id)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should not create foreign key using t.references with :foreign_key => false" do
|
154
|
+
recreate_table(@model) do |t|
|
155
|
+
t.references :user, :foreign_key => false
|
156
|
+
end
|
157
|
+
expect(@model).not_to reference(:users, :id).on(:user_id)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should not create foreign key using t.references with :polymorphic => true" do
|
161
|
+
recreate_table(@model) do |t|
|
162
|
+
t.references :user, :polymorphic => true
|
163
|
+
end
|
164
|
+
expect(@model).not_to reference(:users, :id).on(:user_id)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should create foreign key to the same table on parent_id" do
|
168
|
+
recreate_table(@model) do |t|
|
169
|
+
t.integer :parent_id, foreign_key: true
|
170
|
+
end
|
171
|
+
expect(@model).to reference(@model.table_name, :id).on(:parent_id)
|
172
|
+
end
|
173
|
+
|
174
|
+
actions = [:cascade, :restrict, :nullify, :set_default, :no_action]
|
175
|
+
|
176
|
+
actions.each do |action|
|
177
|
+
if action == :set_default
|
178
|
+
if_action_supported = { :mysql => :skip }
|
179
|
+
if_action_unsupported = { :mysql => :only }
|
180
|
+
else
|
181
|
+
if_action_supported = { :if => true }
|
182
|
+
if_action_unsupported = { :if => false }
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should create and detect on_update #{action.inspect}", if_action_supported do
|
186
|
+
recreate_table @model do |t|
|
187
|
+
t.integer :user_id, :foreign_key => { :on_update => action }
|
188
|
+
end
|
189
|
+
expect(@model).to reference.on(:user_id).on_update(action)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should create and detect on_update #{action.inspect} using shortcut", if_action_supported do
|
193
|
+
recreate_table @model do |t|
|
194
|
+
t.integer :user_id, :on_update => action
|
195
|
+
end
|
196
|
+
expect(@model).to reference.on(:user_id).on_update(action)
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should raise a not-implemented error for on_update => #{action}", if_action_unsupported do
|
200
|
+
expect {
|
201
|
+
recreate_table @model do |t|
|
202
|
+
t.integer :user_id, :foreign_key => { :on_update => action }
|
203
|
+
end
|
204
|
+
}.to raise_error(NotImplementedError)
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should create and detect on_delete #{action.inspect}", if_action_supported do
|
208
|
+
recreate_table @model do |t|
|
209
|
+
t.integer :user_id, :foreign_key => { :on_delete => action }
|
210
|
+
end
|
211
|
+
expect(@model).to reference.on(:user_id).on_delete(action)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should create and detect on_delete #{action.inspect} using shortcut", if_action_supported do
|
215
|
+
recreate_table @model do |t|
|
216
|
+
t.integer :user_id, :on_delete => action
|
217
|
+
end
|
218
|
+
expect(@model).to reference.on(:user_id).on_delete(action)
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should raise a not-implemented error for on_delete => #{action}", if_action_unsupported do
|
222
|
+
expect {
|
223
|
+
recreate_table @model do |t|
|
224
|
+
t.integer :user_id, :foreign_key => { :on_delete => action }
|
225
|
+
end
|
226
|
+
}.to raise_error(NotImplementedError)
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
[false, true, :initially_deferred].each do |status|
|
232
|
+
it "should create and detect deferrable #{status.inspect}", :mysql => :skip do
|
233
|
+
recreate_table @model do |t|
|
234
|
+
t.integer :user_id, :on_delete => :cascade, :deferrable => status
|
235
|
+
end
|
236
|
+
expect(@model).to reference.on(:user_id).deferrable(status)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
it "should use default on_delete action" do
|
241
|
+
with_fk_config(:on_delete => :cascade) do
|
242
|
+
recreate_table @model do |t|
|
243
|
+
t.integer :user_id, foreign_key: true
|
244
|
+
end
|
245
|
+
expect(@model).to reference.on(:user_id).on_delete(:cascade)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should override on_update action per table" do
|
250
|
+
with_fk_config(:on_update => :cascade) do
|
251
|
+
recreate_table @model, :foreign_keys => {:on_update => :restrict} do |t|
|
252
|
+
t.integer :user_id, foreign_key: true
|
253
|
+
end
|
254
|
+
expect(@model).to reference.on(:user_id).on_update(:restrict)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should override on_delete action per table" do
|
259
|
+
with_fk_config(:on_delete => :cascade) do
|
260
|
+
recreate_table @model, :foreign_keys => {:on_delete => :restrict} do |t|
|
261
|
+
t.integer :user_id, foreign_key: true
|
262
|
+
end
|
263
|
+
expect(@model).to reference.on(:user_id).on_delete(:restrict)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
it "should override on_update action per column" do
|
268
|
+
with_fk_config(:on_update => :cascade) do
|
269
|
+
recreate_table @model, :foreign_keys => {:on_update => :restrict} do |t|
|
270
|
+
t.integer :user_id, :foreign_key => { :on_update => :nullify }
|
271
|
+
end
|
272
|
+
expect(@model).to reference.on(:user_id).on_update(:nullify)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
it "should override on_delete action per column" do
|
277
|
+
with_fk_config(:on_delete => :cascade) do
|
278
|
+
recreate_table @model, :foreign_keys => {:on_delete => :restrict} do |t|
|
279
|
+
t.integer :user_id, :foreign_key => { :on_delete => :nullify }
|
280
|
+
end
|
281
|
+
expect(@model).to reference.on(:user_id).on_delete(:nullify)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should raise an error for an invalid on_update action" do
|
286
|
+
expect {
|
287
|
+
recreate_table @model do |t|
|
288
|
+
t.integer :user_id, :foreign_key => { :on_update => :invalid }
|
289
|
+
end
|
290
|
+
}.to raise_error(ArgumentError)
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should raise an error for an invalid on_delete action" do
|
294
|
+
expect {
|
295
|
+
recreate_table @model do |t|
|
296
|
+
t.integer :user_id, :foreign_key => { :on_delete => :invalid }
|
297
|
+
end
|
298
|
+
}.to raise_error(ArgumentError)
|
299
|
+
end
|
300
|
+
|
301
|
+
end
|
302
|
+
|
303
|
+
context "when table is changed" do
|
304
|
+
before(:each) do
|
305
|
+
@model = Post
|
306
|
+
end
|
307
|
+
[false, true].each do |bulk|
|
308
|
+
suffix = bulk ? ' with :bulk option' : ""
|
309
|
+
|
310
|
+
it "should create a foreign key constraint"+suffix, :sqlite3 => :skip do
|
311
|
+
change_table(@model, :bulk => bulk) do |t|
|
312
|
+
t.integer :user_id, foreign_key: true
|
313
|
+
end
|
314
|
+
expect(@model).to reference(:users, :id).on(:user_id)
|
315
|
+
end
|
316
|
+
|
317
|
+
context "migrate down" do
|
318
|
+
it "should remove a foreign key constraint"+suffix, :sqlite3 => :skip do
|
319
|
+
Comment.reset_column_information
|
320
|
+
expect(Comment).to reference(:users, :id).on(:user_id)
|
321
|
+
migration = Class.new ::ActiveRecord::Migration do
|
322
|
+
define_method(:change) {
|
323
|
+
change_table("comments", :bulk => bulk) do |t|
|
324
|
+
t.integer :user_id, foreign_key: true
|
325
|
+
end
|
326
|
+
}
|
327
|
+
end
|
328
|
+
ActiveRecord::Migration.suppress_messages do
|
329
|
+
migration.migrate(:down)
|
330
|
+
end
|
331
|
+
Comment.reset_column_information
|
332
|
+
expect(Comment).not_to reference(:users, :id).on(:user_id)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
it "should create a foreign key constraint using :references"+suffix, :sqlite3 => :skip do
|
337
|
+
change_table(@model, :bulk => bulk) do |t|
|
338
|
+
t.references :user, foreign_key: true
|
339
|
+
end
|
340
|
+
expect(@model).to reference(:users, :id).on(:user_id)
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should create a foreign key constraint using :belongs_to"+suffix, :sqlite3 => :skip do
|
344
|
+
change_table(@model, :bulk => bulk) do |t|
|
345
|
+
t.belongs_to :user, foreign_key: true
|
346
|
+
end
|
347
|
+
expect(@model).to reference(:users, :id).on(:user_id)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
context "when column is added", :sqlite3 => :skip do
|
353
|
+
|
354
|
+
before(:each) do
|
355
|
+
@model = Comment
|
356
|
+
end
|
357
|
+
|
358
|
+
it "should create foreign key" do
|
359
|
+
add_column(:post_id, :integer, foreign_key: true) do
|
360
|
+
expect(@model).to reference(:posts, :id).on(:post_id)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
it "should create foreign key to explicitly given table" do
|
365
|
+
add_column(:author_id, :integer, :foreign_key => { :references => :users }) do
|
366
|
+
expect(@model).to reference(:users, :id).on(:author_id)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
it "should create foreign key to explicitly given table using shortcut" do
|
371
|
+
add_column(:author_id, :integer, :references => :users) do
|
372
|
+
expect(@model).to reference(:users, :id).on(:author_id)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
it "should create foreign key to explicitly given table and column name" do
|
377
|
+
add_column(:author_login, :string, :foreign_key => { :references => [:users, :login]}) do
|
378
|
+
expect(@model).to reference(:users, :login).on(:author_login)
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
it "should create foreign key to the same table on parent_id" do
|
383
|
+
add_column(:parent_id, :integer, foreign_key: true) do
|
384
|
+
expect(@model).to reference(@model.table_name, :id).on(:parent_id)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
it "should use default on_update action" do
|
389
|
+
SchemaPlus::ForeignKeys.config.on_update = :cascade
|
390
|
+
add_column(:post_id, :integer, foreign_key: true) do
|
391
|
+
expect(@model).to reference.on(:post_id).on_update(:cascade)
|
392
|
+
end
|
393
|
+
SchemaPlus::ForeignKeys.config.on_update = nil
|
394
|
+
end
|
395
|
+
|
396
|
+
it "should use default on_delete action" do
|
397
|
+
SchemaPlus::ForeignKeys.config.on_delete = :cascade
|
398
|
+
add_column(:post_id, :integer, foreign_key: true) do
|
399
|
+
expect(@model).to reference.on(:post_id).on_delete(:cascade)
|
400
|
+
end
|
401
|
+
SchemaPlus::ForeignKeys.config.on_delete = nil
|
402
|
+
end
|
403
|
+
|
404
|
+
it "should allow to overwrite default actions" do
|
405
|
+
SchemaPlus::ForeignKeys.config.on_delete = :cascade
|
406
|
+
SchemaPlus::ForeignKeys.config.on_update = :restrict
|
407
|
+
add_column(:post_id, :integer, :foreign_key => { :on_update => :nullify, :on_delete => :nullify}) do
|
408
|
+
expect(@model).to reference.on(:post_id).on_delete(:nullify).on_update(:nullify)
|
409
|
+
end
|
410
|
+
SchemaPlus::ForeignKeys.config.on_delete = nil
|
411
|
+
end
|
412
|
+
|
413
|
+
it "should create foreign key with default name" do
|
414
|
+
add_column(:post_id, :integer, foreign_key: true) do
|
415
|
+
expect(@model).to reference(:posts, :id).with_name("fk_#{@model.table_name}_post_id")
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
protected
|
420
|
+
def add_column(column_name, *args)
|
421
|
+
table = @model.table_name
|
422
|
+
ActiveRecord::Migration.add_column(table, column_name, *args)
|
423
|
+
@model.reset_column_information
|
424
|
+
yield if block_given?
|
425
|
+
ActiveRecord::Migration.remove_column(table, column_name)
|
426
|
+
end
|
427
|
+
|
428
|
+
end
|
429
|
+
|
430
|
+
|
431
|
+
context "when column is changed" do
|
432
|
+
|
433
|
+
before(:each) do
|
434
|
+
@model = Comment
|
435
|
+
end
|
436
|
+
|
437
|
+
context "with foreign keys", :sqlite3 => :skip do
|
438
|
+
|
439
|
+
it "should create foreign key" do
|
440
|
+
change_column :user, :string, :foreign_key => { :references => [:users, :login] }
|
441
|
+
expect(@model).to reference(:users, :login).on(:user)
|
442
|
+
end
|
443
|
+
|
444
|
+
context "and initially references to users table" do
|
445
|
+
|
446
|
+
before(:each) do
|
447
|
+
recreate_table @model do |t|
|
448
|
+
t.integer :user_id, foreign_key: true
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
it "should have foreign key" do
|
453
|
+
expect(@model).to reference(:users)
|
454
|
+
end
|
455
|
+
|
456
|
+
it "should drop foreign key if it is no longer valid" do
|
457
|
+
change_column :user_id, :integer, :foreign_key => { :references => :members }
|
458
|
+
expect(@model).not_to reference(:users)
|
459
|
+
end
|
460
|
+
|
461
|
+
it "should drop foreign key if requested to do so" do
|
462
|
+
change_column :user_id, :integer, :foreign_key => { :references => nil }
|
463
|
+
expect(@model).not_to reference(:users)
|
464
|
+
end
|
465
|
+
|
466
|
+
it "should reference pointed table afterwards if new one is created" do
|
467
|
+
change_column :user_id, :integer, :foreign_key => { :references => :members }
|
468
|
+
expect(@model).to reference(:members)
|
469
|
+
end
|
470
|
+
|
471
|
+
it "should maintain foreign key if it's unaffected by change" do
|
472
|
+
change_column :user_id, :integer, :default => 0
|
473
|
+
expect(@model).to reference(:users)
|
474
|
+
end
|
475
|
+
|
476
|
+
end
|
477
|
+
|
478
|
+
end
|
479
|
+
|
480
|
+
protected
|
481
|
+
def change_column(column_name, *args)
|
482
|
+
table = @model.table_name
|
483
|
+
ActiveRecord::Migration.suppress_messages do
|
484
|
+
ActiveRecord::Migration.change_column(table, column_name, *args)
|
485
|
+
@model.reset_column_information
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
end
|
490
|
+
|
491
|
+
context "when column is removed", :sqlite3 => :skip do
|
492
|
+
before(:each) do
|
493
|
+
@model = Comment
|
494
|
+
recreate_table @model do |t|
|
495
|
+
t.integer :post_id, foreign_key: true
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
it "should remove a foreign key" do
|
500
|
+
expect(@model).to reference(:posts)
|
501
|
+
remove_column(:post_id)
|
502
|
+
expect(@model).not_to reference(:posts)
|
503
|
+
end
|
504
|
+
|
505
|
+
protected
|
506
|
+
def remove_column(column_name)
|
507
|
+
table = @model.table_name
|
508
|
+
ActiveRecord::Migration.suppress_messages do
|
509
|
+
ActiveRecord::Migration.remove_column(table, column_name)
|
510
|
+
@model.reset_column_information
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
|
516
|
+
context "when table is renamed" do
|
517
|
+
|
518
|
+
before(:each) do
|
519
|
+
@model = Comment
|
520
|
+
recreate_table @model do |t|
|
521
|
+
t.integer :user_id, foreign_key: true
|
522
|
+
t.integer :xyz, :index => true
|
523
|
+
end
|
524
|
+
ActiveRecord::Migration.suppress_messages do
|
525
|
+
ActiveRecord::Migration.rename_table @model.table_name, :newname
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
it "should rename foreign key constraints", :sqlite3 => :skip do
|
530
|
+
expect(ActiveRecord::Base.connection.foreign_keys(:newname).first.name).to match(/newname/)
|
531
|
+
end
|
532
|
+
|
533
|
+
end
|
534
|
+
|
535
|
+
|
536
|
+
context "when table with more than one fk constraint is renamed", :sqlite3 => :skip do
|
537
|
+
|
538
|
+
before(:each) do
|
539
|
+
@model = Comment
|
540
|
+
recreate_table @model do |t|
|
541
|
+
t.integer :user_id
|
542
|
+
t.integer :member_id
|
543
|
+
end
|
544
|
+
ActiveRecord::Migration.suppress_messages do
|
545
|
+
ActiveRecord::Migration.rename_table @model.table_name, :newname
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
it "should rename foreign key constraints" do
|
550
|
+
names = ActiveRecord::Base.connection.foreign_keys(:newname).map(&:name)
|
551
|
+
expect(names.grep(/newname/)).to eq(names)
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
def recreate_table(model, opts={}, &block)
|
556
|
+
ActiveRecord::Migration.suppress_messages do
|
557
|
+
ActiveRecord::Migration.create_table model.table_name, opts.merge(:force => true), &block
|
558
|
+
end
|
559
|
+
model.reset_column_information
|
560
|
+
end
|
561
|
+
|
562
|
+
def change_table(model, opts={}, &block)
|
563
|
+
ActiveRecord::Migration.suppress_messages do
|
564
|
+
ActiveRecord::Migration.change_table model.table_name, opts, &block
|
565
|
+
end
|
566
|
+
model.reset_column_information
|
567
|
+
end
|
568
|
+
|
569
|
+
end
|
570
|
+
|