hobofields 0.8.5 → 0.8.6

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.
@@ -1,30 +1,39 @@
1
1
  # HoboFields - Migration Generator
2
2
 
3
3
  Note that these doctests are good tests but not such good docs. The migration generator doesn't really fit well with the doctest concept of a single IRB session. As you'll see, there's a lot of jumping-through-hoops and doing stuff that no normal user of the migration generator would ever do.
4
+ {.hidden}
4
5
 
5
6
  Firstly, in order to test the migration generator outside of a full Rails stack, there's a few things we need to do. First off we need to configure ActiveSupport for auto-loading
7
+ {.hidden}
6
8
 
7
9
  >> require 'rubygems'
8
10
  >> require 'activesupport'
9
- >> Dependencies.load_paths << '.'
10
- >> Dependencies.mechanism = :require
11
-
12
- And we'll require:
13
-
14
11
  >> require 'activerecord'
15
- >> require 'action_controller'
16
- >> require 'hobofields'
12
+ {.hidden}
17
13
 
18
14
  We also need to get ActiveRecord set up with a database connection
15
+ {.hidden}
19
16
 
20
17
  >> mysql_database = "hobofields_doctest"
18
+ >> system "mysqladmin --force drop #{mysql_database} 2> /dev/null"
21
19
  >> system("mysqladmin create #{mysql_database}") or raise "could not create database"
22
20
  >> ActiveRecord::Base.establish_connection(:adapter => "mysql",
23
21
  :database => mysql_database,
24
22
  :host => "localhost")
23
+ {.hidden}
25
24
 
26
- OK we're ready to get going.
25
+ Some load path manipulation you shouldn't need:
26
+ {.hidden}
27
27
 
28
+ >> $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '../../hobofields/lib')
29
+ >> $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '../../hobosupport/lib')
30
+ {.hidden}
31
+
32
+ And we'll require:
33
+ {.hidden}
34
+
35
+ >> require 'hobosupport'
36
+ >> require 'hobofields'
28
37
 
29
38
  ## The migration generator -- introduction
30
39
 
@@ -62,17 +71,17 @@ The migration generator only takes into account classes that use HoboFields, i.e
62
71
  Here we see a simple `create_table` migration along with the `drop_table` down migration
63
72
 
64
73
  >>
65
- class Advert < ActiveRecord::Base
66
- fields do
67
- name :string
68
- end
69
- end
74
+ class Advert < ActiveRecord::Base
75
+ fields do
76
+ name :string
77
+ end
78
+ end
70
79
  >> up, down = HoboFields::MigrationGenerator.run
71
80
  >> up
72
- =>""
73
- create_table :adverts do |t|
74
- t.string :name
75
- end
81
+ =>
82
+ "create_table :adverts do |t|
83
+ t.string :name
84
+ end"
76
85
  >> down
77
86
  => "drop_table :adverts"
78
87
 
@@ -85,13 +94,13 @@ Normally we would run the generated migration with `rake db:create`. We can achi
85
94
  We'll define a method to make that easier next time
86
95
 
87
96
  >>
88
- def migrate(renames={})
89
- up, down = HoboFields::MigrationGenerator.run(renames)
90
- puts up
91
- ActiveRecord::Migration.class_eval(up)
92
- ActiveRecord::Base.send(:subclasses).each { |model| model.reset_column_information }
93
- [up, down]
94
- end
97
+ def migrate(renames={})
98
+ up, down = HoboFields::MigrationGenerator.run(renames)
99
+ puts up
100
+ ActiveRecord::Migration.class_eval(up)
101
+ ActiveRecord::Base.send(:subclasses).each { |model| model.reset_column_information }
102
+ [up, down]
103
+ end
95
104
 
96
105
  We'll have a look at the migration generator in more detail later, first we'll have a look at the extra features HoboFields has added to the model.
97
106
 
@@ -101,22 +110,22 @@ We'll have a look at the migration generator in more detail later, first we'll h
101
110
  If we add a new field to the model, the migration generator will add it to the database.
102
111
 
103
112
  >>
104
- class Advert
105
- fields do
106
- name :string
107
- body :text
108
- published_at :datetime
109
- end
110
- end
113
+ class Advert
114
+ fields do
115
+ name :string
116
+ body :text
117
+ published_at :datetime
118
+ end
119
+ end
111
120
  >> up, down = migrate
112
121
  >> up
113
- =>""
114
- add_column :adverts, :body, :text
115
- add_column :adverts, :published_at, :datetime
122
+ =>
123
+ "add_column :adverts, :body, :text
124
+ add_column :adverts, :published_at, :datetime"
116
125
  >> down
117
- =>""
118
- remove_column :adverts, :body
119
- remove_column :adverts, :published_at
126
+ =>
127
+ "remove_column :adverts, :body
128
+ remove_column :adverts, :published_at"
120
129
  >>
121
130
 
122
131
  ### Remove fields
@@ -124,12 +133,12 @@ If we add a new field to the model, the migration generator will add it to the d
124
133
  If we remove a field from the model, the migration generator removes the database column. Note that we have to explicitly clear the known fields to achieve this in rdoctest -- in a Rails context you would simply edit the file
125
134
 
126
135
  >> Advert.field_specs.clear # not normally needed
127
- class Advert < ActiveRecord::Base
128
- fields do
129
- name :string
130
- body :text
131
- end
132
- end
136
+ class Advert < ActiveRecord::Base
137
+ fields do
138
+ name :string
139
+ body :text
140
+ end
141
+ end
133
142
  >> up, down = migrate
134
143
  >> up
135
144
  => "remove_column :adverts, :published_at"
@@ -141,18 +150,18 @@ If we remove a field from the model, the migration generator removes the databas
141
150
  Here we rename the `name` field to `title`. By default the generator sees this as removing `name` and adding `title`.
142
151
 
143
152
  >> Advert.field_specs.clear # not normally needed
144
- class Advert < ActiveRecord::Base
145
- fields do
146
- title :string
147
- body :text
148
- end
149
- end
153
+ class Advert < ActiveRecord::Base
154
+ fields do
155
+ title :string
156
+ body :text
157
+ end
158
+ end
150
159
  >> # Just generate - don't run the migration:
151
160
  >> up, down = HoboFields::MigrationGenerator.run
152
161
  >> up
153
- =>""
154
- add_column :adverts, :title, :string
155
- remove_column :adverts, :name
162
+ =>
163
+ "add_column :adverts, :title, :string
164
+ remove_column :adverts, :name"
156
165
  >> down
157
166
  =>""
158
167
  remove_column :adverts, :title
@@ -176,13 +185,13 @@ Let's apply that change to the database
176
185
 
177
186
  >> Advert.attr_type :title
178
187
  => String
179
- >>
180
- class Advert
181
- fields do
182
- title :text
183
- body :text
184
- end
185
- end
188
+ >>
189
+ class Advert
190
+ fields do
191
+ title :text
192
+ body :text
193
+ end
194
+ end
186
195
  >> up, down = HoboFields::MigrationGenerator.run
187
196
  >> up
188
197
  => "change_column :adverts, :title, :text, :limit => nil"
@@ -193,15 +202,17 @@ Let's apply that change to the database
193
202
  ### Add a default
194
203
 
195
204
  >>
196
- class Advert
197
- fields do
198
- title :string, :default => "Untitled"
199
- body :text
200
- end
201
- end
205
+ class Advert
206
+ fields do
207
+ title :string, :default => "Untitled"
208
+ body :text
209
+ end
210
+ end
202
211
  >> up, down = migrate
203
- >> up
204
- => 'change_column :adverts, :title, :string, :default => "Untitled", :limit => 255'
212
+ >> up.split(',').slice(0,3).join(',')
213
+ => 'change_column :adverts, :title, :string'
214
+ >> up.split(',').slice(3,2).sort.join(',')
215
+ => ' :default => "Untitled", :limit => 255'
205
216
  >> down
206
217
  => "change_column :adverts, :title, :string"
207
218
 
@@ -209,24 +220,23 @@ Let's apply that change to the database
209
220
  ### Limits
210
221
 
211
222
  >>
212
- class Advert
213
- fields do
214
- price :integer, :limit => 4
215
- end
216
- end
223
+ class Advert
224
+ fields do
225
+ price :integer, :limit => 2
226
+ end
227
+ end
217
228
  >> up, down = HoboFields::MigrationGenerator.run
218
229
  >> up
219
- "add_column :advert, :integer, :limit => 4"
220
-
230
+ => "add_column :adverts, :price, :integer, :limit => 2"
221
231
 
222
232
  Note that limit on a decimal column is ignored (use :scale and :precision)
223
233
 
224
234
  >>
225
- class Advert
226
- fields do
227
- price :decimal, :limit => 4
228
- end
229
- end
235
+ class Advert
236
+ fields do
237
+ price :decimal, :limit => 4
238
+ end
239
+ end
230
240
  >> up, down = HoboFields::MigrationGenerator.run
231
241
  >> up
232
242
  => "add_column :adverts, :price, :decimal"
@@ -240,62 +250,62 @@ Cleanup
240
250
 
241
251
  HoboFields extends the `belongs_to` macro so that it also declares the foreign-key field.
242
252
 
243
- >>
244
- class Advert
245
- belongs_to :category
246
- end
247
- >> up, down = HoboFields::MigrationGenerator.run
248
- >> up
249
- => 'add_column :adverts, :category_id, :integer'
250
- >> down
251
- => 'remove_column :adverts, :category_id'
253
+ >>
254
+ class Advert
255
+ belongs_to :category
256
+ end
257
+ >> up, down = HoboFields::MigrationGenerator.run
258
+ >> up
259
+ => 'add_column :adverts, :category_id, :integer'
260
+ >> down
261
+ => 'remove_column :adverts, :category_id'
252
262
 
253
263
  Cleanup:
254
264
 
255
- >> Advert.field_specs.delete(:category_id)
265
+ >> Advert.field_specs.delete(:category_id)
256
266
 
257
267
  If you specify a custom foreign key, the migration generator observes that:
258
268
 
259
- >>
260
- class Advert
261
- belongs_to :category, :foreign_key => "c_id"
262
- end
263
- >> up, down = HoboFields::MigrationGenerator.run
264
- >> up
265
- => 'add_column :adverts, :c_id, :integer'
266
- >> down
267
- => 'remove_column :adverts, :c_id'
269
+ >>
270
+ class Advert
271
+ belongs_to :category, :foreign_key => "c_id"
272
+ end
273
+ >> up, down = HoboFields::MigrationGenerator.run
274
+ >> up
275
+ => 'add_column :adverts, :c_id, :integer'
276
+ >> down
277
+ => 'remove_column :adverts, :c_id'
268
278
 
269
279
  Cleanup:
270
280
 
271
- >> Advert.field_specs.delete(:c_id)
281
+ >> Advert.field_specs.delete(:c_id)
272
282
 
273
283
 
274
284
  ### Timestamps
275
285
 
276
286
  `updated_at` and `created_at` can be declared with the shorthand `timestamps`
277
287
 
278
- >>
279
- class Advert
280
- fields do
281
- timestamps
282
- end
283
- end
284
- >> up, down = HoboFields::MigrationGenerator.run
285
- >> up
286
- =>""
287
- add_column :adverts, :created_at, :datetime
288
- add_column :adverts, :updated_at, :datetime
289
- >> down
290
- =>""
291
- remove_column :adverts, :created_at
292
- remove_column :adverts, :updated_at
293
- >>
288
+ >>
289
+ class Advert
290
+ fields do
291
+ timestamps
292
+ end
293
+ end
294
+ >> up, down = HoboFields::MigrationGenerator.run
295
+ >> up
296
+ =>
297
+ "add_column :adverts, :created_at, :datetime
298
+ add_column :adverts, :updated_at, :datetime"
299
+ >> down
300
+ =>
301
+ "remove_column :adverts, :created_at
302
+ remove_column :adverts, :updated_at"
303
+ >>
294
304
 
295
305
  Cleanup:
296
306
 
297
- >> Advert.field_specs.delete(:updated_at)
298
- >> Advert.field_specs.delete(:created_at)
307
+ >> Advert.field_specs.delete(:updated_at)
308
+ >> Advert.field_specs.delete(:created_at)
299
309
 
300
310
 
301
311
  ### Rename a table
@@ -303,13 +313,13 @@ Cleanup:
303
313
  The migration generator respects the `set_table_name` declaration, although as before, we need to explicitly tell the generator that we want a rename rather than a create and a drop.
304
314
 
305
315
  >>
306
- class Advert
307
- set_table_name "ads"
308
- fields do
309
- title :string, :default => "Untitled"
310
- body :text
311
- end
312
- end
316
+ class Advert
317
+ set_table_name "ads"
318
+ fields do
319
+ title :string, :default => "Untitled"
320
+ body :text
321
+ end
322
+ end
313
323
  >> up, down = HoboFields::MigrationGenerator.run(:adverts => :ads)
314
324
  >> up
315
325
  => "rename_table :adverts, :ads"
@@ -334,25 +344,24 @@ Dropping tables is where the automatic down-migration really comes in handy:
334
344
  >> up
335
345
  => "drop_table :adverts"
336
346
  >> down
337
- =>""
338
- create_table "adverts", :force => true do |t|
339
- t.text "body"
340
- t.string "title", :default => "Untitled"
341
- end
342
- >>
347
+ =>
348
+ "create_table "adverts", :force => true do |t|
349
+ t.text "body"
350
+ t.string "title", :default => "Untitled"
351
+ end"
343
352
 
344
353
  ### Rename a table
345
354
 
346
355
  As with renaming columns, we have to tell the migration generator about the rename. Here we create a new class 'Advertisement'. Remember 'Advert' is being ignored so it's as if we renamed the definition in our models directory.
347
356
 
348
357
  >>
349
- class Advertisement < ActiveRecord::Base
350
- fields do
351
- title :string, :default => "Untitled"
352
- body :text
353
- end
354
- end
355
- >> up, down = HoboFields::MigrationGenerator.run(:adverts => :advertisements)
358
+ class Advertisement < ActiveRecord::Base
359
+ fields do
360
+ title :string, :default => "Untitled"
361
+ body :text
362
+ end
363
+ end
364
+ >> up, down = HoboFields::MigrationGenerator.run(:adverts => :advertisements)
356
365
  >> up
357
366
  => "rename_table :adverts, :advertisements"
358
367
  >> down
@@ -366,20 +375,22 @@ Now that we've seen the renaming we'll switch the 'ignore' setting to ignore tha
366
375
 
367
376
  ### Adding an STI subclass
368
377
 
369
- Adding a subclass should introduce the 'type' column and no other changes
378
+ Adding a subclass or two should introduce the 'type' column and no other changes
370
379
 
371
- >>
372
- class FancyAdvert < Advert
373
- end
374
- >> up, down = HoboFields::MigrationGenerator.run
375
- >> up
376
- => "add_column :adverts, :type, :string"
377
- >> down
378
- => "remove_column :adverts, :type"
380
+ >>
381
+ class FancyAdvert < Advert
382
+ end
383
+ class SuperFancyAdvert < FancyAdvert
384
+ end
385
+ >> up, down = HoboFields::MigrationGenerator.run
386
+ >> up
387
+ => "add_column :adverts, :type, :string"
388
+ >> down
389
+ => "remove_column :adverts, :type"
379
390
 
380
391
  Cleanup
381
392
 
382
- >> Advert.field_specs.delete(:type)
393
+ >> Advert.field_specs.delete(:type)
383
394
 
384
395
 
385
396
  ## Coping with multiple changes
@@ -400,43 +411,62 @@ First let's confirm we're in a known state. One model, 'Advert', with a string '
400
411
 
401
412
  >> Advert.field_specs.clear
402
413
  >>
403
- class Advert
404
- fields do
405
- name :string, :default => "No Name"
406
- body :text
407
- end
408
- end
414
+ class Advert
415
+ fields do
416
+ name :string, :default => "No Name"
417
+ body :text
418
+ end
419
+ end
409
420
  >> up, down = HoboFields::MigrationGenerator.run(:adverts => {:title => :name})
410
421
  >> up
411
- =>""
412
- rename_column :adverts, :title, :name
413
- change_column :adverts, :name, :string, :default => "No Name", :limit => 255
422
+ =>
423
+ "rename_column :adverts, :title, :name
424
+ change_column :adverts, :name, :string, :default => "No Name", :limit => 255"
414
425
  >> down
415
- =>""
416
- rename_column :adverts, :name, :title
417
- change_column :adverts, :title, :string, :default => "Untitled"
418
- >>
426
+ =>
427
+ 'rename_column :adverts, :name, :title
428
+ change_column :adverts, :title, :string, :default => "Untitled"'
419
429
 
420
430
 
421
431
  ### Rename a table and add a column
422
432
 
423
- >> HoboFields::MigrationGenerator.ignore_models << :advert
424
- class Ad < ActiveRecord::Base
425
- fields do
426
- title :string, :default => "Untitled"
427
- body :text
428
- created_at :datetime
429
- end
430
- end
433
+ >> HoboFields::MigrationGenerator.ignore_models += [:advert, :fancy_advert, :super_fancy_advert]
434
+ >>
435
+ class Ad < ActiveRecord::Base
436
+ fields do
437
+ title :string, :default => "Untitled"
438
+ body :text
439
+ created_at :datetime
440
+ end
441
+ end
431
442
  >> up, down = HoboFields::MigrationGenerator.run(:adverts => :ads)
432
443
  >> up
433
- =>""
434
- rename_table :adverts, :ads
444
+ =>
445
+ "rename_table :adverts, :ads
435
446
 
436
- add_column :ads, :created_at, :datetime
447
+ add_column :ads, :created_at, :datetime"
437
448
  >>
438
-
439
449
 
440
- ## Cleanup
450
+ ## Legacy Keys
451
+
452
+ HoboFields has some support for legacy keys.
453
+
454
+ >> Advert.field_specs.clear
455
+ >>
456
+ class Advert
457
+ fields do
458
+ name :string, :default => "No Name"
459
+ body :text
460
+ end
461
+ set_primary_key "advert_id"
462
+ end
463
+ >> up, down = HoboFields::MigrationGenerator.run(:adverts => {:id => :advert_id})
464
+ >> up
465
+ =>
466
+ "rename_column :adverts, :id, :advert_id
467
+
468
+ Cleanup
469
+ {.hidden}
441
470
 
442
- >> system "mysqladmin --force drop #{mysql_database}"
471
+ >> system "mysqladmin --force drop #{mysql_database} 2> /dev/null"
472
+ {.hidden}