<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
Step-by-step demonstration
</title>
<script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
<script type="text/javascript">
window.onload = function() {
settings = {
tl: { radius: 10 },
tr: { radius: 10 },
bl: { radius: 10 },
br: { radius: 10 },
antiAlias: true,
autoPad: true,
validTags: ["div"]
}
var versionBox = new curvyCorners(settings, document.getElementById("version"));
versionBox.applyCornersToAll();
}
</script>
</head>
<body>
<div id="main">
<h1>Step-by-step demonstration</h1>
<div id="version" class="clickable" onclick='document.location = "http://railsbundle.com/dist/JavaScript Unit Testing.tar.gz"; return false'>
<p>Get Version</p>
<a href="http://railsbundle.com/dist/JavaScript Unit Testing.tar.gz" class="numbers">2.0.0</a>
<a href="http://railsbundle.com/dist/JavaScript Unit Testing.tar.gz" class="numbers"><img src="images/logo_bundle.png" width="50" height="51" alt="Logo Bundle" border=0></a>
</div>
<p>In this demo we’ll create a blog; because that’s what blogs are for: being
demonstrations of web frameworks.</p>
<p>The demonstration uses new features of Rails 2.0 and the snippets in this bundle.</p>
<h2>A New App</h2>
<pre>rails blog
cd blog
mate .</pre>
<h2>Add some models</h2>
<pre>ruby script/generate model Post subject:string body:text</pre>
<p>This creates a 001_create_posts migration with a create_table:</p>
<p><pre class='syntax'><span class="ident">create_table</span> <span class="symbol">:posts</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">string</span> <span class="symbol">:subject</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">text</span> <span class="symbol">:body</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">timestamps</span>
<span class="keyword">end</span></pre></p>
<h2>Sexy Migration support</h2>
<p>If you put the cursor on the line after <code>t.text :body</code>, type <code>t.</code> and press ⇥. Select “Create boolean column” (by pressing 0), and type “published” into the template field. If nothing happened when you pressed ⇥, check that when you opened the migrations file you’ve selected the bundle “Ruby on Rails”.</p>
<p>Note that another <code>t.</code> was created on the next line! Press ⇥ and the cursor will be placed after it. You can now press ⇥ again to create another column, or delete this line.</p>
<p>Here, delete the extraneous <code>t.</code> line (⌃ ⇧ K). And save the file (⌘ S).</p>
<p>Run the migrations, either from the prompt:</p>
<pre><code>rake db:migrate</code></pre>
<p>or directly from the editor with ⌃ | (Ctrl-Pipeline), and choosing option “Migrate to Current”.</p>
<h2>Post fixtures</h2>
<p>Update the <code>test/fixtures/posts.yml</code> file as:</p>
<p><pre class='syntax'><span class="key">published</span><span class="punct">:</span>
<span class="key">subject</span><span class="punct">:</span> Some article
<span class="key">body</span><span class="punct">:</span> A test article
<span class="key">published</span><span class="punct">:</span> true
<span class="key">nonpublished</span><span class="punct">:</span>
<span class="key">body</span><span class="punct">:</span> Still writing this one</pre></p>
<p>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.</p>
<h2>Public blog controller</h2>
<p>Create a controller for our blog, either via the command prompt:</p>
<pre><code>ruby script/generate controller blog</code></pre>
<p>or directly from the editor with ⌃ |, and choosing option “Call Generate Script”, choose “Controller”, give it the name “blog”, and empty the list of actions.</p>
<p>Now open <code>blog_controller_test.rb</code>. To find this file quickly press ⌘ T, enter bct, and select the file.</p>
<p>Note how much cleaner functional tests are now via <code>ActionController::TestCase</code>.</p>
<p>Let’s do some <span class="caps">TDD</span>. First, delete the <code>test_truth</code> dummy method.</p>
<p>To create a test to show a list of blog articles:</p>
<pre><code>deftg</code></pre>
<p>and ⇥ gives:</p>
<p><pre class='syntax'><span class="keyword">def </span><span class="method">test_should_get_action</span>
<span class="attribute">@model</span> <span class="punct">=</span> <span class="ident">models</span><span class="punct">(</span><span class="symbol">:fixture_name</span><span class="punct">)</span>
<span class="ident">get</span> <span class="symbol">:action</span><span class="punct">,</span> <span class="symbol">:id</span> <span class="punct">=></span> <span class="attribute">@model</span><span class="punct">.</span><span class="ident">to_param</span>
<span class="ident">assert_response</span> <span class="symbol">:success</span>
<span class="keyword">end</span></pre></p>
<p>Type <code>index</code> to replace <code>action</code>. Press ⇥, and then ⌫ to remove the first line, then press ⇥ three times and then ⌫ to remove the <code>:id => @model.to_param</code> part. The press ⇥ again to go to the end of the method. Now we have:</p>
<p><pre class='syntax'><span class="keyword">def </span><span class="method">test_should_get_index</span>
<span class="ident">get</span> <span class="symbol">:index</span>
<span class="ident">assert_response</span> <span class="symbol">:success</span>
<span class="keyword">end</span></pre></p>
<p>Now type <code>asg</code>, press ⇥, and type <code>posts</code>, and press ⇥ again. This creates an instance variable lookup within an assertion:</p>
<p><pre class='syntax'><span class="ident">assert</span><span class="punct">(</span><span class="ident">posts</span> <span class="punct">=</span> <span class="ident">assigns</span><span class="punct">(</span><span class="symbol">:posts</span><span class="punct">),</span> <span class="punct">"</span><span class="string">Cannot find @posts</span><span class="punct">")</span></pre></p>
<p>Now, let’s assert the <span class="caps">HTML</span> format.</p>
<p>Type <code>ass</code> and press ⇥. Type <code>div#posts</code>, press ⇥ and ⌫, then ⇥ twice to place the cursor within the <code>assert_select</code> block:</p>
<p><pre class='syntax'><span class="ident">assert_select</span> <span class="punct">'</span><span class="string">div#posts</span><span class="punct">'</span> <span class="keyword">do</span>
<span class="keyword">end</span></pre></p>
<p>Now we’ll check that the <code>@posts</code> objects are represented in the <code>div#posts</code> element.</p>
<p>With the cursor inside the <code>assert_select</code>:</p>
<p>Type <code>ass</code>, press ⇥, type <code>div.post</code>, press ⇥ twice, and type <code>count</code> (to replace the <code>text</code>). Now press ⇥ again, and type <code>posts.size</code>. Press ⇥ a final time (it will highlight the <code>do...end</code> block), and press ⌫.</p>
<p>Our test method is now finished:</p>
<p><pre class='syntax'><span class="keyword">def </span><span class="method">test_should_get_index</span>
<span class="ident">get</span> <span class="symbol">:index</span>
<span class="ident">assert_response</span> <span class="symbol">:success</span>
<span class="ident">assert</span><span class="punct">(</span><span class="ident">posts</span> <span class="punct">=</span> <span class="ident">assigns</span><span class="punct">(</span><span class="symbol">:posts</span><span class="punct">),</span> <span class="punct">"</span><span class="string">Cannot find @posts</span><span class="punct">")</span>
<span class="ident">assert_select</span> <span class="punct">'</span><span class="string">div#posts</span><span class="punct">'</span> <span class="keyword">do</span>
<span class="ident">assert_select</span> <span class="punct">'</span><span class="string">div.post</span><span class="punct">',</span> <span class="symbol">:count</span> <span class="punct">=></span> <span class="ident">posts</span><span class="punct">.</span><span class="ident">size</span>
<span class="keyword">end</span>
<span class="keyword">end</span></pre></p>
<p><span class="caps">NOTE</span>: there is also a <code>deftp</code> snippet for functional tests to create a <span class="caps">POST</span> 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></p>
<h2>Controller actions</h2>
<p>To navigate to <code>blog_controller.rb</code> there are three options:</p>
<ul>
<li>press ⇧ ⌥ ⌘ ↓, and select “Controller” from the drop-down list</li>
<li>press ⌥ ⌘ ↓ and you’ll go directly to the controller (toggles between the two files)</li>
<li>press ⌘ T, type <code>bc</code>, choose the file, press ↩.</li>
</ul>
<p>Add the <code>index</code> action method:</p>
<p><pre class='syntax'><span class="keyword">def </span><span class="method">index</span>
<span class="attribute">@posts</span> <span class="punct">=</span> <span class="constant">Post</span><span class="punct">.</span><span class="ident">find_all_by_published</span><span class="punct">(</span><span class="constant">true</span><span class="punct">)</span>
<span class="keyword">end</span></pre></p>
<h2>Action views</h2>
<p>To create/navigate to the view, press ⇧ ⌥ ⌘ ↓ and select “View” (like above). Or press ⌥ ⌘ ↓ to toggle between a controller method and it’s view.</p>
<p>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.</p>
<p>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 ⇧ ⌥ ⌘ ↓ or ⌥ ⌘ ↓. Also note that the cursor must be within the scope of a method for ⇧ ⌥ ⌘ ↓ or ⌥ ⌘ ↓ to work.</p>
<p>Press enter to accept <code>index.html.erb</code>. You are taken to the new file.</p>
<p>Let’s create <span class="caps">HTML</span> to match the earlier tests.</p>
<p>Type <code>div</code> and press ⇥ twice, then type <code>posts</code> and press ⇥:</p>
<p><pre class='syntax'><div id="posts">
</div></pre></p>
<p>Inside the <code>div</code> element, type <code>for</code> and press ⇥. This expands into a large ERb-enabled for-loop. Type <code>@posts</code>, press ⇥, type <code>post</code> and press ⇥. The cursor is now inside the for-loop.</p>
<p>Inside the for-loop, type: <code>div</code> and press ⇥. Press ⌫, and type <code> class='post'</code> and press ⇥ to enter the <code>div</code> element.</p>
<p>Create a <code><%= %></code> element (⌃ >). If you press ⌃ > 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 ⌃ > again starts at <code><%= %></code> again.</p>
<p>Enter <code>post.body</code> within the ERb template field.</p>
<p>Actually, we’ll need to show the subject too, so above the <code><%= post.body %></code> line (press ↑ followed by ⌘ ↩)
type ‘h3’, and press ⌃ < (LessThan), then ⌃ > (GreatherThan), and <code>post.subject</code>.</p>
<p>The resulting line is: <code><h3><%= post.subject %></h3></code></p>
<p>Move the cursor down between <code><% else %></code> and <code><% end %></code>.</p>
<p>Create a simple element <code><p></p></code> (⌃ ⇧ W or ⌃ <). You can change the element type here. Just press ⇥ 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.</p>
<p>Our <code>index.html.erb</code> template is now:</p>
<p><pre class='syntax'><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></p>
<p>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 ⌃ \ and press 2 for “Test Functionals”</p>
<p>As yet, we have no way for users to leave comments.</p>
<h2>Foxy Fixtures</h2>
<p>Create a comment model:</p>
<pre><code>ruby script/generate model Comment body:text name:string post:references</code></pre>
<p>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.</p>
<p>The generated <code>create_table</code> in <code>002_create_comments.rb</code> is:</p>
<p><pre class='syntax'><span class="ident">create_table</span> <span class="symbol">:comments</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">text</span> <span class="symbol">:body</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">string</span> <span class="symbol">:name</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">references</span> <span class="symbol">:post</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">timestamps</span>
<span class="keyword">end</span></pre></p>
<p>Run <code>rake db:migrate</code>, or directly from the editor with ⌃ | and choose option “Migrate to Current”.</p>
<p>Now create some comment fixtures so we can look at Foxy Fixtures. Open <code>text/fixtures/comments.yml</code> (⌘ T, type <code>cy</code>, press ↩).</p>
<p>By default, the generated <code>comments.yml</code> starts like:</p>
<pre>one:
body: MyText
name: MyString
post:
two:
body: MyText
name: MyString
post:</pre>
<p>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.</p>
<p>Put the cursor after <code>post:</code> and press ⌥ ⎋. A drop-down box appears with the names of the <code>posts.yml</code> fixtures. Select <code>published</code> and press ↩. Repeat for the 2nd fixture. This gives us:</p>
<pre>one:
body: MyText
name: MyString
post: published
two:
body: MyText
name: MyString
post: published</pre>
<h2>Associations</h2>
<p>To enable the Foxy Fixtures, we need to add associations to the model classes.</p>
<p>You can now quickly go from a fixtures file (we’re in comments.yml) to the model file (⇧ ⌥ ⌘ ↓).</p>
<p>Within <code>comment.rb</code> model, create a new line within the class, and type <code>bt</code> and press ⇥. Type <code>post</code>. This creates a snippet:</p>
<p><pre class='syntax'><span class="ident">belongs_to</span> <span class="symbol">:post</span><span class="punct">,</span> <span class="symbol">:class_name</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">Post</span><span class="punct">",</span> <span class="symbol">:foreign_key</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">post_id</span><span class="punct">"</span></pre></p>
<p>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.</p>
<p>Press ⇥ and ⌫ to remove the <code>:class_name</code> and <code>:foreign_key</code> options. The <code>Comment</code> class is now:</p>
<p><pre class='syntax'><span class="keyword">class </span><span class="class">Comment</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
<span class="ident">belongs_to</span> <span class="symbol">:post</span>
<span class="keyword">end</span></pre></p>
<p>Now go to the <code>Post</code> class. Press ⌘ T and type <code>post</code> and select the model file, and press ↩.</p>
<p>Create a new line within the <code>Post</code> class (⌘ ↩). Type <code>hm</code> and press ⇥ to generate a <code>has_many</code> association. Type <code>comment</code>, and the resulting snippet is:</p>
<p><pre class='syntax'><span class="ident">has_many</span> <span class="symbol">:comments</span><span class="punct">,</span> <span class="symbol">:class_name</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">comment</span><span