public
Description: Ruby on Rails TextMate bundle [Learn it with PeepCode - http://peepcode.com/products/textmate-for-rails-2]
Homepage: http://groups.google.com/group/rubyonrails-textmate
Clone URL: git://github.com/drnic/ruby-on-rails-tmbundle.git
Search Repo:
Click here to lend your support to: ruby-on-rails-tmbundle and make a donation at www.pledgie.com !
100644 739 lines (486 sloc) 30.313 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
h1. Step-by-step demonstration
 
In this demo we'll create a blog; because that's what blogs are for: being
demonstrations of web frameworks.
 
The demonstration uses new features of Rails 2.0 and the snippets in this bundle.
 
h2. A New App
 
<pre>rails blog
cd blog
mate .</pre>
 
h2. Add some models
 
<pre>ruby script/generate model Post subject:string body:text</pre>
 
This creates a 001_create_posts migration with a create_table:
 
<pre syntax="ruby">create_table :posts do |t|
  t.string :subject
  t.text :body
 
  t.timestamps
end</pre>
 
h2. Sexy Migration support
 
If you put the cursor on the line after <code>t.text :body</code>, type <code>t.</code> and press TAB. Select "Create boolean column" (by pressing 0), and type "published" into the template field. If nothing happened when you pressed TAB, check that when you opened the migrations file you've selected the bundle "Ruby on Rails".
 
Note that another <code>t.</code> was created on the next line! Press TAB and the cursor will be placed after it. You can now press TAB again to create another column, or delete this line.
 
Here, delete the extraneous <code>t.</code> line (CONTROL SHIFT K). And save the file (COMMAND S).
 
Run the migrations, either from the prompt:
 
    rake db:migrate
 
or directly from the editor with CONTROL | (Ctrl-Pipeline), and choosing option "Migrate to Current".
 
 
h2. Post fixtures
 
Update the <code>test/fixtures/posts.yml</code> file as:
 
<pre syntax="yaml">published:
  subject: Some article
  body: A test article
  published: true
 
nonpublished:
  body: Still writing this one</pre>
 
Note, in Rails 2.0 fixtures no longer have explicit ids. Later on we'll look at snippets for using Foxy Fixtures with auto-completion for associations.
 
h2. Public blog controller
 
Create a controller for our blog, either via the command prompt:
 
    ruby script/generate controller blog
 
or directly from the editor with CONTROL |, and choosing option "Call Generate Script", choose "Controller", give it the name "blog", and empty the list of actions.
 
Now open <code>blog_controller_test.rb</code>. To find this file quickly press COMMAND T, type <code>bct</code>, and select the file.
 
Note how much cleaner functional tests are now via <code>ActionController::TestCase</code>.
 
Let's do some TDD. First, delete the <code>test_truth</code> dummy method.
 
To create a test to show a list of blog articles:
 
    deftg
 
and TAB gives:
 
<pre syntax="ruby">def test_should_get_action
  @model = models(:fixture_name)
  get :action, :id => @model.to_param
  assert_response :success
 
end</pre>
 
Type <code>index</code> to replace <code>action</code>. Press TAB, and then BACKSPACE to remove the first line, then press TAB three times and then BACKSPACE to remove the <code>:id => @model.to_param</code> part. The press TAB again to go to the end of the method. Now we have:
 
<pre syntax="ruby">def test_should_get_index
  get :index
  assert_response :success
 
end</pre>
 
Now type <code>asg</code>, press TAB, and type <code>posts</code>, and press TAB again. This creates an instance variable lookup within an assertion:
 
<pre syntax="ruby">assert(posts = assigns(:posts), "Cannot find @posts")</pre>
 
Now, let's assert the HTML format.
 
Type <code>ass</code> and press TAB. Type <code>div#posts</code>, press TAB and BACKSPACE, then TAB twice to place the cursor within the <code>assert_select</code> block:
 
<pre syntax="ruby">assert_select 'div#posts' do
 
end</pre>
 
Now we'll check that the <code>@posts</code> objects are represented in the <code>div#posts</code> element.
 
With the cursor inside the <code>assert_select</code>:
 
Type <code>ass</code>, press TAB, type <code>div.post</code>, press TAB twice, and type <code>count</code> (to replace the <code>text</code>). Now press TAB again, and type <code>posts.size</code>. Press TAB a final time (it will highlight the <code>do...end</code> block), and press BACKSPACE.
 
Our test method is now finished:
 
<pre syntax="ruby">def test_should_get_index
  get :index
  assert_response :success
  assert(posts = assigns(:posts), "Cannot find @posts")
  assert_select 'div#posts' do
    assert_select 'div.post', :count => posts.size
  end
end</pre>
 
NOTE: there is also a <code>deftp</code> snippet for functional tests to create a POST test stub.
To memorize: <code>deftg</code> stands for <code>define test get</code> and <code>deftp</code> stands for <code>define test post</code>
 
h2. Controller actions
 
To navigate to <code>blog_controller.rb</code> there are three options:
 
* press SHIFT OPTION COMMAND DOWN, and select "Controller" from the drop-down list
* press OPTION COMMAND DOWN and you'll go directly to the controller (toggles between the two files)
* press COMMAND T, type <code>bc</code>, choose the file, press RETURN.
 
Add the <code>index</code> action method:
 
<pre syntax="ruby">def index
  @posts = Post.find_all_by_published(true)
end</pre>
 
h2. Action views
 
To create/navigate to the view, press SHIFT OPTION COMMAND DOWN and select "View" (like above). Or press OPTION COMMAND DOWN to toggle between a controller method and it's view.
 
As there are no <code>app/views/blog/index*</code> files, it will prompt you to create a blank view file. By default it guesses <code>index.html.erb</code> (because the method was named <code>index</code>), but of course you can change that in the dialog box.
 
If instead you got the message "blog_controller.rb does not have a view", note that you first need to save the controller file before hitting SHIFT OPTION COMMAND DOWN or OPTION COMMAND DOWN. Also note that the cursor must be within the scope of a method for SHIFT OPTION COMMAND DOWN or OPTION COMMAND DOWN to work.
 
Press enter to accept <code>index.html.erb</code>. You are taken to the new file.
 
Let's create HTML to match the earlier tests.
 
Type <code>div</code> and press TAB twice, then type <code>posts</code> and press TAB:
 
<pre syntax="html"><div id="posts">
 
</div></pre>
 
Inside the <code>div</code> element, type <code>for</code> and press TAB. This expands into a large ERb-enabled for-loop. Type <code>@posts</code>, press TAB, type <code>post</code> and press TAB. The cursor is now inside the for-loop.
 
Inside the for-loop, type: <code>div</code> and press TAB. Press BACKSPACE, and type <code> class='post'</code> and press TAB to enter the <code>div</code> element.
 
Create a <code><%= %></code> element (CONTROL >). If you press CONTROL > again, it toggles to <code><% %></code>, and then again and it becomes <code><%- -%></code>, and again and it becomes <code><%# %></code> (a Ruby comment). Pressing CONTROL > again starts at <code><%= %></code> again.
 
Enter <code>post.body</code> within the ERb template field.
 
Actually, we'll need to show the subject too, so above the <code><%= post.body %></code> line (press UP followed by COMMAND RETURN)
type 'h3', and press CONTROL < (LessThan), then CONTROL > (GreatherThan), and <code>post.subject</code>.
 
The resulting line is: <code><h3><%= post.subject %></h3></code>
 
Move the cursor down between <code><% else %></code> and <code><% end %></code>.
 
Create a simple element <code><p></p></code> (CONTROL SHIFT W or CONTROL <). You can change the element type here. Just press TAB to go inside the element. Type <code>There are no posts available to read. All y'all come back soon, yer hear.</code> because its funny.
 
Our <code>index.html.erb</code> template is now:
 
<pre syntax="html"><div id="posts">
  <% if !@posts.blank? %>
    <% for post in @posts %>
      <div class="post">
        <h3><%= post.subject %></h3>
        <%= post.body %>
      </div>
    <% end %>
  <% else %>
    <p>There are no posts available to read. All y'all come back soon, yer hear.</p>
  <% end %>
 
</div></pre>
 
If we run our functional tests they now pass: run either from the command prompt with <code>rake test:functionals</code> or directly from the editor by pressing CONTROL \ and press 2 for "Test Functionals"
 
As yet, we have no way for users to leave comments.
 
h2. Foxy Fixtures
 
Create a comment model:
 
    ruby script/generate model Comment body:text name:string post:references
 
Note: here <code>post:references</code> is effectively the same as <code>post_id:integer</code>. Within the generated migration it creates <code>t.reference :post</code>. There is also a <code>t.</code> and <code>tcr</code> snippet for references, as for other standard datatypes, which helps setup polymorphic associations.
 
The generated <code>create_table</code> in <code>002_create_comments.rb</code> is:
 
<pre syntax="ruby">create_table :comments do |t|
  t.text :body
  t.string :name
  t.references :post
 
  t.timestamps
end</pre>
 
Run <code>rake db:migrate</code>, or directly from the editor with CONTROL | and choose option "Migrate to Current".
 
Now create some comment fixtures so we can look at Foxy Fixtures. Open <code>text/fixtures/comments.yml</code> (COMMAND T, type <code>cy</code>, press RETURN).
 
By default, the generated <code>comments.yml</code> starts like:
 
<pre>one:
  body: MyText
  name: MyString
  post:
 
two:
  body: MyText
  name: MyString
  post:</pre>
 
The <code>post</code> fields replace the rails1.2 <code>post_id</code> fields. Now, we can specify the <code>post.yml</code> labels for a post. From above we have <code>published</code> and <code>unpublished</code>. It can be hard to remember what fixtures we have, so there is a key-combo helper.
 
Put the cursor after <code>post:</code> and press OPTION ESCAPE. A drop-down box appears with the names of the <code>posts.yml</code> fixtures. Select <code>published</code> and press RETURN. Repeat for the 2nd fixture. This gives us:
 
<pre>one:
  body: MyText
  name: MyString
  post: published
 
two:
  body: MyText
  name: MyString
  post: published</pre>
 
h2. Associations
 
To enable the Foxy Fixtures, we need to add associations to the model classes.
 
You can now quickly go from a fixtures file (we're in comments.yml) to the model file (SHIFT OPTION COMMAND DOWN).
 
Within <code>comment.rb</code> model, create a new line within the class, and type <code>bt</code> and press TAB. Type <code>post</code>. This creates a snippet:
 
<pre syntax="ruby">belongs_to :post, :class_name => "Post", :foreign_key => "post_id"</pre>
 
The class name and foreign key are now generated from the association name. You can change them by tabbing across. But, we only need the default, so we can delete these options.
 
Press TAB and BACKSPACE to remove the <code>:class_name</code> and <code>:foreign_key</code> options. The <code>Comment</code> class is now:
 
<pre syntax="ruby">class Comment < ActiveRecord::Base
  belongs_to :post
end</pre>
 
Now go to the <code>Post</code> class. Press COMMAND T and type <code>post</code> and select the model file, and press RETURN.
 
Create a new line within the <code>Post</code> class (COMMAND RETURN). Type <code>hm</code> and press TAB to generate a <code>has_many</code> association. Type <code>comment</code>, and the resulting snippet is:
 
<pre syntax="ruby">has_many :comments, :class_name => "comment", :foreign_key => "class_name_id"</pre>
 
We don't need the options. So press TAB once and then BACKSPACE.
 
<pre syntax="ruby">class Post < ActiveRecord::Base
  has_many :comments
end</pre>
 
Note: there is also a <code>has_many :through</code> snippet. Type <code>hmt</code> and TAB to activate it.
 
Finally, we can run our tests since adding the <code>Comment</code> model + fixtures (CONTROL \).
 
<pre>rake test</pre>
 
h2. Routes
 
Open the routes file (COMMAND T, type <code>routes</code> and press RETURN).
 
Change the routes file to:
 
<pre syntax="ruby">ActionController::Routing::Routes.draw do |map|
  map.resources :posts
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'
end</pre>
 
h2. Creating Posts
 
From the <code>Post</code> model class (<code>post.rb</code>) you can now quickly navigate to a controller
of the same name. It supports either singular or plural controller names, but
will default to the plural name, which is the REST/resources preferred name.
 
To create a <code>PostsController</code>, use the 'Go To' hot key (as above) SHIFT OPTION COMMAND DOWN and select 'Controller'. As there is no <code>post_controller.rb</code> nor <code>posts_controller.rb</code> it will create a <code>posts_controller.rb</code> controller file; which is what we want here.
 
Note; at this stage you could use the Rails 2.0 <code>scaffold</code> generator to create the <code>posts_controller.rb</code> (and tests and routes).
 
In the blank file, we need to create a controller class.
 
Type <code>cla</code> and TAB, and select "Create controller class". Type <code>Posts</code> and TAB,
<code>post</code> and TAB, and finally, <code>Post</code> and TAB. This leaves the cursor in the middle
of the generated class:
 
<pre syntax="ruby">class PostsController < ApplicationController
  before_filter :find_post
 
 
 
  private
  def find_post
    @post = Post.find(params[:id]) if params[:id]
  end
end</pre>
 
h2. TDD for Posts controller
 
Currently there is not a functional test for our <code>posts_controller.rb</code>. To create it, use the 'Go To' hot key (SHIFT OPTION COMMAND DOWN) and select 'Functional Test'. This will create a blank file.
 
Type <code>cla</code> and TAB, and select "Create functional test class".
Type <code>Posts</code> and TAB. (The functional test class name
should match the controller class, with <code>Test</code> suffixed to it).
 
The functional test class snippet gives you a <code>deft</code> stub. If you
press TAB now, it creates a generic test method snippet:
 
<pre syntax="ruby">def test_case_name
 
end</pre>
 
Instead, we will use the <code>deftg</code> (GET request) and <code>deftp</code> (POST request) snippets.
 
Create a test for the <code>index</code>, <code>new</code> and <code>edit</code> actions. For <code>index</code> and <code>new</code>, we can delete the <code>@model = models(:fixture_name)</code>,
etc parts.
 
To test for the <code>create</code> action, type <code>deftp</code> and TAB. Type <code>create</code> and TAB, type <code>post</code> and TAB, type BACKSPACE and TAB, and again BACKSPACE and TAB. Now enter in a hash of the values to pass in for the test, say <code>:subject => 'Test', :body => 'Some body', :published => '1'</code>. The result should look like:
 
<pre syntax="ruby">def test_should_post_create
  post :create, :post => { :subject => 'Test', :body => 'Some body', :published => '1' }
  assert_response :redirect
 
end</pre>
 
On the line after the <code>assert_response</code> expression, we'll test
for where we want to be redirected to.
 
If you type <code>art</code> you create an old-style <code>assert_redirected_to :action => "index"</code>
snippet.
 
In addition there are now various <code>assert_redirected_to</code> snippets that
use resourceful routes:
 
* artp - <code>assert_redirected_to model_path(@model)</code>
* artpp - <code>assert_redirected_to models_path</code>
* artnp - <code>assert_redirected_to parent_child_path(@parent, @child)</code>
* artnpp - <code>assert_redirected_to parent_child_path(@parent)</code>
 
As we'll see later, this naming scheme is used for other snippets that
use resourceful routes, like <code>link_to</code> and <code>redirect_to</code>.
 
Type <code>artpp</code> and TAB, and type <code>post</code>, to assert that the <code>create</code>
action must redirect to the index page.
 
The final <code>test_should_post_create</code> method is:
 
<pre syntax="ruby">def test_should_post_create
  post :create, :post => { :subject => 'Test', :body => 'Some body', :published => '1' }
  assert_response :redirect
  assert_redirected_to posts_path
end</pre>
 
Running our tests (<code>rake test:functionals</code> or CONTROL \) shows all these new tests failing.
 
h2. Views
 
Go back to the <code>posts_controller.rb</code> file (OPTION COMMAND DOWN).
 
Now add three actions - <code>index</code>, <code>new</code> and <code>edit</code>. New methods can be created
with the <code>def</code> snippet:
 
<pre syntax="ruby">class PostsController < ApplicationController
  before_filter :find_post
 
  def index
    @posts = Post.find(:all)
  end
 
  def new
    @post = Post.new
  end
 
  def edit
  end
 
  private
  def find_post
    @post = Post.find(params[:id]) if params[:id]
  end
end</pre>
 
Note: the <code>index</code> method could be created by typing <code>def</code>, TAB, <code>index</code>, TAB, <code>@posts = Post.fina</code>, TAB, BACKSPACE.
 
Now we need templates for the <code>index</code>, <code>new</code> and <code>edit</code> actions.
 
Place the cursor inside the <code>index</code> method,
and use the 'Go To' hot key (SHIFT OPTION COMMAND DOWN)
and select 'View'. A dialog box will pop up asking for the name of the new
template (as there are no <code>app/views/posts/index*</code> files). By default, the
suffix is now <code>.html.erb</code> rather than the old <code>.rhtml</code>. Press RETURN,
to accept <code>index.html.erb</code> as your template name.
 
Let's just create a simple table showing the Posts.
 
Type <code>table</code> and CONTROL < to generate <code><table></table></code>, and
press RETURN to put the tags on separate lines.
 
Do the same to create a <code><tbody></tbody></code> element.
 
Inside the <code><tbody></tbody></code> we want to iterate over the <code>@posts</code>,
one per <code><tr></tr></code> row.
 
Press CONTROL >, three times, to create a <code><%- -%></code> tag. Inside it
type <code>@posts.each do |post|</code>.
 
On the next line (COMMAND RETURN), type <code>end</code> and TAB, to create <code><% end -%></code>.
We now have a Ruby block within this ERb template.
 
Inside the block, create a <code><tr></tr></code> element, and within it
create a <code><td></td></code> element. We'll skip over anything fancy
here, and just put the post's subject here.
 
Type <code>post.subject</code> and select it. Now press CONTROL > to wrap
the selected text inside <code><%= post.subject %></code>.
 
The resulting <code>index.html.erb</code> is:
 
<pre syntax="html"><table>
  <tbody>
    <%- @posts.each do |post| -%>
      <tr>
        <td><%= post.subject %></td>
      </tr>
    <% end -%>
  </tbody>
</table></pre>
 
h2. Forms
 
Place the cursor inside the <code>new</code> method,
and use the 'Go To' hot key (SHIFT OPTION COMMAND DOWN)
and select 'View'. Press RETURN to accept <code>new.html.erb</code>.
 
Inside the blank <code>new.html.erb</code> file, type <code>ffe</code> and press TAB, and type <code>post</code>
and press TAB twice:
 
<pre syntax="html"><%= error_messages_for :post %>
<% form_for @post do |f| -%>
 
<% end -%></pre>
 
<code>form_for</code> is the Rails 2.0 preferred helper for managing forms, and
there are now snippets for common form_for helpers. There are <code>ff</code> and <code>ffe</code>
snippets; the former does not have the error messages section.
 
To create a label and text field for the <code>subject</code> attribute:
 
Create a <code><p></p></code> block (Press CONTROL <, then TAB, then RETURN).
Type <code>f.</code> and TAB, and select "Label". Type <code>subject</code>, press TAB and press BACKSPACE.
Create a <code><br /></code> (CONTROL RETURN).
Type <code>f.</code> and TAB, and select "Text Field". Type <code>subject</code>.
 
This gives us:
 
<pre syntax="html"><%= error_messages_for :post %>
<% form_for @post do |f| -%>
  <p>
    <%= f.label :subject %><br />
    <%= f.text_field :subject %>
  </p>
<% end -%></pre>
 
Now repeat for <code>body</code> and <code>published</code> fields.
 
Note, for <code>published</code>, you might change the label to <code>Published yet?</code> by tabbing
into the default string file.
 
Finally, add a "Submit" button using the <code>f.</code> snippet tab completion.
 
Start <code>script/server</code> from the prompt and you can now view this form at [http://localhost:3000/posts/new](http://localhost:3000/posts/new)
 
The final form is:
 
<pre syntax="html"><%= error_messages_for :post %>
<% form_for @post do |f| -%>
  <p>
    <%= f.label :subject %><br />
    <%= f.text_field :subject %>
  </p>
  <p>
    <%= f.label :body %><br />
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.label :published, "Published yet?" %><br />
    <%= f.check_box :published %>
  </p>
  <p>
    <%= f.submit "Submit" %>
  </p>
<% end -%></pre>
 
Note: if you got <code><br></code> when hitting CONTROL RETURN instead of <code><br /></code> then you might want to go to the preferences of TextMate (COMMAND ,), choose tab "Advanced", choose "Shell Variables", click the + sign to add a new shell variable, and give it the name <code>TM_XHTML</code> and a value of <code> /</code>
 
h2. Partials
 
The form we just created is exactly the same as the form required for the <code>edit.html.erb</code> template.
 
Instead of copy+pasting it into the <code>edit.html.erb</code> file, we'll create a partial
template.
 
Select the entire form (COMMAND A), and press CONTROL SHIFT H and a dialog box appears.
Type in <code>form</code> and press RETURN.
 
You'll notice a new file <code>_form.html.erb</code> has appeared which contains the code you had selected,
while the code in the file <code>new.html.erb</code> has been replaced by:
 
    <%= render :partial => 'form' %>
 
Now copy and paste this into the <code>edit.html.erb</code> file. To create this file,
return to the controller (from the <code>new.html.erb</code> file, press OPTION COMMAND DOWN), go to the <code>edit</code> action,
and use OPTION COMMAND DOWN again to create the <code>edit.html.erb</code> template file.
 
h2. Link helpers
 
At the bottom of the <code>new.html.erb</code> we want a link back to the list of all posts
(within the posts controller, not the public blog controller). This
will be the <code>index</code> action, and will be accessible via the resources route
<code>posts_path</code>.
 
There are several <code>link_to</code> snippets that support the resources routes:
 
* lip - <code><%= link_to "link text...", model_path(@model) %></code>
* lipp - <code><%= link_to "link text...", models_path %></code>
* linp - <code><%= link_to "link text...", parent_child_path(@parent, @child) %></code>
* linpp - <code><%= link_to "link text...", parent_child_path(@parent) %></code>
* lim - <code><%= link_to model.name, model_path(model) %></code>
 
The tab stop points are in useful places.
 
So, to create our link to the posts page, type <code>lipp</code> and TAB, type
<code>Show all posts</code>, press TAB twice and type <code>post</code>.
 
h2. Controllers: <code>respond_to</code> and <code>redirect_to</code>
 
Now we'll add a <code>create</code> action to the <code>posts_controller.rb</code>. Let's go there (OPTION COMMAND DOWN).
 
Below the <code>edit</code> method type <code>def</code> and TAB, and type
<code>create</code> and TAB. Now fill out the <code>create</code> action like:
 
<pre syntax="ruby">def create
  @post = Post.new(params[:post])
  if @post.save
 
  else
 
  end
end</pre>
 
Place the cursor in the <code>true</code> section of the <code>if</code> statement.
Type <code>repp</code> and TAB to create a <code>redirect_to</code> expression. Press TAB
again and replace the selected text with <code>post</code>.
 
Like the various <code>link_to</code> snippets, there are matching <code>redirect_to</code>
snippets.
 
* rep - <code>redirect_to(model_path(@model))</code>
* repp - <code>redirect_to(models_path)</code>
* renp - <code>redirect_to(parent_child_path(@parent, @child))</code>
* renpp - <code>redirect_to(parent_child_path(@parent))</code>
 
There are tab stops in useful places.
 
In the <code>false</code> section of the <code>if</code> expression, we'll demonstrate the
<code>respond_to</code> block. There are two ways to generate a <code>respond_to</code> block.
 
Type <code>rest</code> and TAB, and you get a standard empty block you can work with:
 
<pre syntax="ruby">respond_to do |wants|
  wants.html { }
end</pre>
 
Press TAB twice to get inside the <code>wants.html</code> block, type <code>ra</code>, press TAB, then type <code>new</code>. The final block is:
 
<pre syntax="ruby">respond_to do |wants|
  wants.html { render :action => "new" }
end</pre>
 
Alternately, there is the "upgrade" hot key (SHIFT COMMAND H), where you can convert some
existing selected code, into a <code>respond_to</code> block.
 
Select the whole line containing the <code>redirect_to</code> expression from the
<code>true</code> section of the <code>if</code> statement (SHIFT COMMAND L).
 
Press SHIFT COMMAND H and the line is replaced with:
 
<pre syntax="ruby">respond_to do |wants|
  wants.html do
    redirect_to(posts_path)
  end
  wants.js { }
end</pre>
 
The <code>js</code> is the first tab stop. The point of this hot key is to instantly
refactor your existing html respond code, and support a second response
format.
 
For now remove the line with <code>wants.js</code> (CONTROL SHIFT K).
 
The completed <code>create</code> action is:
 
<pre syntax="ruby">def create
  @post = Post.new(params[:post])
  if @post.save
    respond_to do |wants|
      wants.html do
        redirect_to(posts_path)
      end
    end
  else
    respond_to do |wants|
      wants.html { render :action => "new" }
    end
  end
end</pre>
 
Yes you'd probably only have one <code>respond_to</code> block, but this is a
demo so I am taking the scenic route.
 
h2. Our application so far
 
In the browser, we can create posts via [http://localhost:3000/posts/new](http://localhost:3000/posts/new)
and then view them as a blog visitor at [http://localhost:3000/blog](http://localhost:3000/blog).
 
h2. Some more migrations
 
We're looking for the following additions:
 
* rename the column <code>name</code> of table <code>comments</code> to <code>author</code>
* add a new column <code>author_url</code> to table <code>comments</code>
* add an index to the column <code>post_id</code> of the <code>comments</code> table
 
Let's try to do this all in one migrations file. Start Quick Migration (CONTROL SHIFT M). Let's name it <code>ModifyComments</code>. A new migrations file <code>003_modify_comments.rb</code> is created and opened, and the cursor is placed behind the <code>mtab</code> trigger. For now delete <code>mtab</code> and instead enter <code>mcol</code> and press TAB. Choose <code>Rename / Rename Column</code> (3). Type <code>comments</code> TAB <code>name</code> TAB <code>author</code> TAB RETURN.
 
Again type <code>mcol</code> and TAB. This time choose <code>Add / Remove Column</code> (1). Type <code>comments</code> TAB <code>author_url</code>, then TAB twice, and press RETURN.
 
Now type <code>mind</code> and TAB. Choose <code>Add / Remove Index</code> (1). Type <code>comments</code> TAB <code>post_id</code>.
 
The end result looks like this:
 
<pre syntax="ruby">class ModifyComments < ActiveRecord::Migration
  def self.up
    rename_column :comments, :name, :author
    add_column :comments, :author_url, :string
    add_index :comments, :post_id
  end
 
  def self.down
    remove_index :comments, :post_id
    remove_column :comments, :author_url
    rename_column :comments, :author, :name
  end
end</pre>
 
Notice how the <code>down</code> method calls are in reversed order of the <code>up</code> method calls.
 
Save the file (COMMAND S) and migrate to current (CONTROL |).
 
Be sure to modify the comments fixture file. Go there (COMMAND T, press <code>cy</code>, choose <code>comments.yml</code>). Rename <code>name</code> to <code>author</code> and add a row for <code>author_url</code> for each comment. Check your tests again (CONTROL \, choose option 1). All tests should pass.
 
Futhermore we'd like to know when a post was published. To do this we'll want the following modifications:
 
* keep track of the datetime when a post was published.
* remove the column published from the posts table because it can be determined if a post is published by looking at whether or not a value is present for the published date.
 
Start Quick Migration (CONTROL SHIFT M). Let's name it <code>AddPublishedAtForPosts</code>. A new migrations file <code>004_add_published_at_for_posts.rb</code> is created and opened, and the cursor is placed behind the <code>mtab</code> trigger. Again delete <code>mtab</code> and instead enter <code>mcol</code> and press TAB. Choose <code>Add / Remove Column</code> (1). Type <code>posts</code> TAB <code>published_at</code> TAB <code>datetime</code> TAB and RETURN.
 
Again type <code>mcol</code> and TAB. Choose <code>Remove / Add Column</code> (5). Type <code>posts</code> TAB <code>published</code> and press TAB twice.
 
The end result looks like this:
 
<pre syntax="ruby">class AddPublishedAtForPosts < ActiveRecord::Migration
  def self.up
    add_column :posts, :published_at, :datetime
    remove_column :posts, :published
  end
 
  def self.down
    add_column :posts, :published, :boolean
    remove_column :posts, :published_at
  end
end</pre>
 
Notice how the <code>Remove / Add Column</code> command automagically determined in the <code>down</code> method the column type of column <code>published</code> to be a <code>boolean</code>. It determines this by looking at the current state of your <code>db/schema.rb</code> file.
 
Save the file (COMMAND S) and migrate to current (CONTROL |).
 
Now we need to modify the posts fixtures file. Go there (COMMAND T, type <code>pyml</code>, choose <code>posts.yml</code>). Replace the line <code>published: true</code> by <code>published_at: 2008-1-1</code>.
 
Modify the posts functional test, first go there (SHIFT OPTION COMMAND DOWN, choose "Go to Functional Test"). Replace <code>:published => '1'</code> by <code>:published_at => Date.new(2008, 1, 1)</code>.
 
Modify the post model, first go there (SHIFT OPTION COMMAND DOWN, choose "Go to Model"). Have the code look like:
 
<pre syntax="ruby">class Post < ActiveRecord::Base
  has_many :comments
 
  def published
    !self.published_at.nil?
  end
 
  def published=(publish)
    if publish
      self.published_at = DateTime.now if self.published_at.nil?
    else
      self.published_at = nil
    end
  end
end</pre>
 
Modify the <code>blog_controller.rb</code> file. Replace <code>Post.find_all_by_published(true)</code> by <code>Post.find(:all, :conditions => "published_at IS NOT NULL")</code>.
 
Finally, check your tests again (CONTROL \). All tests should pass.
 
 
h1. TODO
 
* Model snippets (validates_...)
* link_to(model) (ltm)
* RJS demo