Skip to content
This repository
tree: acec0ccddf
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 649 lines (511 sloc) 35.213 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
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Geddy - A Structured Node.js Framework</title>
    <meta name="description" content="">
    <meta name="author" content="">

    <meta name="viewport" content="width=device-width">

    <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
    <!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->

    <!--TODO: Use the cdn instead of the line below <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>-->
    <script src="file:///home/miguelmadero/code/geddy/templates/base/public/js/jquery.min.js"></script>
    <script src="js/bootstrap.min.js"></script>

    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/bootstrap.min.responsive.css">

    <link rel="stylesheet" href="js/google-code-prettify/prettify.css">
    <script src="js/google-code-prettify/prettify.js"></script>

    <!-- Le styles -->
    <style>
      @media (min-width: 980px) {
        body {
          padding-top: 60px;
        }
      }

      code {
        color: #777;
      }

      p, li {
        line-height: 200%;
      }

      h2, h3 {
        line-height: 200%;
      }

      .tutorial pre.prettyprint {
        margin: 20px 0;
      }

      .navbar {
        box-shadow: 0px 0px 3px #000;
        border-bottom: 1px solid #999;
      }

      .code-box {
        padding-top: 28px;
      }

      .code-box .syntaxhighlighter {
        box-shadow: 0px 0px 3px #000;
        border-radius: 3px;
      }

      .container > .hero-unit {
        background-color: rgba(200, 200, 200, .5);
        box-shadow: 0px 0px 3px #bababa;
        border: 1px solid #EDEDED;
      }

      #content {
        background: #efefef;
        border-radius: 3px;
        box-shadow: 0px 0px 2px #ccc;
      }

      .tutorial {
        padding: 20px 40px;
        line-height: 150%;
      }

      @media (max-width: 480px) {
        .hero-unit {
          padding: 20px 20px 30px 20px;
        }
        .hero-unit h1 {
          font-size: 32px;
        }
        .hero-unit p {
          font-size: 12px;
        }
      }
    </style>

    <!-- Le fav and touch icons -->
    <link rel="shortcut icon" href="images/favicon.ico">
    <link rel="apple-touch-icon" href="images/apple-touch-icon.png">
    <link rel="apple-touch-icon" sizes="72x72" href="images/apple-touch-icon-72x72.png">
    <link rel="apple-touch-icon" sizes="114x114" href="images/apple-touch-icon-114x114.png">
  </head>

  <!-- TODO: add background-image: url(http://subtlepatterns.com/patterns/whitey.png);-->
  <body style="background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-position: initial initial; background-repeat: initial initial; " onload="prettyPrint()">

    <div class="navbar navbar-fixed-top">
      <div class="navbar-inner">
        <div class="container">
          <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
            <span class="i-bar"><i class="icon-chevron-down icon-white"></i></span>
          </a>
          <a class="brand" href="index.html">GeddyJS</a>
          <div class="nav-collapse">
            <ul class="nav">
              <li><a href="index.html">Home</a></li>
              <li><a href="features.html">Features</a></li>
              <li class="active"><a href="tutorial.html">Tutorial</a></li>
              <!--<li><a href="docs.html">Docs</a></li>-->
            </ul>
            <ul class="nav pull-right">
              <li><a href="http://github.com/mde/geddy">Get it on Github</a></li>
            </ul>
          </div><!--/.nav-collapse -->
        </div>
      </div>
    </div>

    <div class="container">
      <div class="hero-unit">
        <h1>Tutorial</h1>
        <p class="pull-right">A quick guide to Geddy</p>
      </div>
      <div class="row">
        <div class="span3">

          <!--Content navigation-->
          <div class="well">
            <h5>Introduction</h5>
            <ul>
              <li><a href="#installing">Installing Geddy</a></li>
              <li><a href="#executable">Geddy Executable</a></li>
            </ul>
            <h5>App tutorials</h5>
            <ul>
              <li><a href="#scaffolding">Using scaffolding</a></li>
              <li><a href="#resources">Using resources</a></li>
            </ul>
          </div>
        </div>

        <!--Content-->
        <div class="span9" id="content">
          <div class="tutorial">

            <h2 id="introduction">Welcome to the Geddy Tutorial</h2>

            <p>In this tutorial we'll learn how to use Geddy by creating a simple todo manager applciation. We will create two applications one using scaffolding and one using resources. See the <a href="https://github.com/mde/geddy/tree/master/examples/todo_app">finished version</a>.</p>

            <h4>In this tutorial we'll cover:</h4>
            <ul>
              <li>Creating a Geddy application</li>
              <li>Learning how to use the Geddy executable</li>
              <li>Using Geddy models</li>
              <li>How views in Geddy work</li>
              <li>How to use controllers to tie everything together</li>
            </ul>

            <h2 id="installing">Installing Geddy</h2>
            <p>If you haven't already, install <a href="http://nodejs.org#download">Node</a> on your machine.</p>

            <p>Next, install Geddy from <a href="http://npmjs.org/">NPM</a>, this will also install <a href="https://github.com/mde/jake">Jake</a>:</p>
            <pre class="prettyprint">$ [sudo] npm install -g geddy</pre>

            <p>We need to install it globally (-g) so we can use geddy generators or start the server. More on this later.
            Note: installing packages globally may require super-user access. </p>


            <h2 id="executable">Using the Geddy command</h2>
            <p>Now that we have Geddy installed we need to learn how to use its command from the CLI. There are a few commands and options that help with the development process of creating applications using Geddy. Here we will go over what each of them do. Note if no arguments are given Geddy will start up the server if it's a Geddy application, otherwise it will show the help dialog.</p>

            <h4>Options:</h4>
            <ul>
              <li><code>--environment</code>, <code>-e</code>: Environment to use</li>
              <li><code>--port</code>, <code>-p</code>: Port to connect server to</li>
              <li><code>--workers</code>, <code>-w</code>: Number of workers to use (default: 1)</li>
              <li><code>--debug</code>, <code>-d</code>: Sets the log level to output debug messages to console</li>
              <li><code>--jade</code>, <code>-j</code>: When generating views, use Jade templates(Default: EJS)</li>
              <li><code>--handle</code>, <code>-H</code>: When generating views, use Handlebars templates(Default: EJS)</li>
              <li><code>--mustache</code>, <code>-m</code>: When generating views, use Mustache templates(Default: EJS)</li>
              <li><code>--version</code>, <code>-v</code>: Output the version of Geddy installed</li>
              <li><code>--help</code>, <code>-h</code>: Output the list of commands and options</li>
            </ul>

            <h4>Commands:</h4>
            <ul>
              <li><code>app &lt;name&gt;</code>: Create a new Geddy application</li>
              <li><code>resource &lt;name&gt; [model attributes]</code>: Create a new Geddy resource. Resources include a model, controller and a route</li>
              <li><code>scaffold &lt;name&gt; [model attributes]</code>: Creates a new Geddy scaffolding. Scaffolding includes everything Resources have as well as views</li>
              <li><code>secret</code>: Generate a new application secret in `config/environment`</li>
              <li><code>controller &lt;name&gt;</code>: Generate a new controller including an index view and a route</li>
              <li><code>model &lt;name&gt; [model attributes]</code>: Generate a new model</li>
              <li><code>console</code>: opens a console in the context of geddy</li>
            </ul>

            <h4>How to use Geddy commands</h4>
            <p>Each of Geddy's commands(<code>app</code>, <code>resource</code>, <code>controller</code>, etc.) take a command or set of commands(excluding <code>secret</code> and <code>console</code>). Here we'll learn how to use those commands.</p>

            <ul>
              <li><code>app</code> takes a single argument being the name you'd like, then it will generate a base application. If no name is given the command will fail.</li>

              <li><code>secret</code> doesn't take any arguments, it will find your <code>config/environment</code> file and create a new secret in it deleting any other secret.</li>

              <li><code>controller</code> takes a single argument being a name. It will create a new controller, a route and an index view. If you also include the options <code>--jade</code>, <code>--handle</code> or <code>--mustache</code> you can substitute the template language to your liking.</li>

              <li><code>model</code> takes one or more arguments, the first being a name and the others being a set of model properties. We won't go over model properties right now but you can learn about them in the next section. This will create a new model including the model properties given.</li>

              <li><code>resource</code> takes one or more arguments, the first being a name and the others being a set of model properties. This will create a controller, a model including the given model properties and a resource route.</li>

              <li><code>scaffold</code> takes one or more arguments, the first being a name and the others being a set of model properties. Scaffolding includes a controller, a model including the given model properties as well as a default model adapter a resource route and will create all views. If you also include the options <code>--jade</code>, <code>--handle</code> or <code>--mustache</code> you can substitute the template language to your liking.</li>
              <li><code>console</code> doesn't take any arguments, it will start a geddy console.
            </ul>

            <h4 id="model-properties">Model properties</h4>
            <p>There are a three commands(<code>resource</code>, <code>model</code> and <code>scaffold</code>) that also include model property arguments. This is a list seperated by spaces that include the property, its type and an optional default setting. Below are some examples of how they are used in the commands.</p>

            <pre class="prettyprint">$ geddy scaffold user name:string</pre>
            <p>The example above will create our normal scaffolding and include a <code>name</code> property of type <code>string</code>. If no type is given it will default to <code>string</code>.</p>

            <pre class="prettyprint">$ geddy scaffold user name:default</pre>
            <p>This example creates scaffolding but includes <code>name</code> as the default property that will be used when displaying the content in the views. In this example the property <code>name</code> is given the type <code>string</code> because no type was given, you could of also writte <code>name:string:default</code>, or you could've used a different type of course. The <code>default</code> setting also includes an alias called <code>def</code>. If no default property is given Geddy will use <code>id</code> as the display property.</property>

            <pre class="prettyprint">$ geddy scaffold user name:default id:int</pre>
            <p>This time we used <code>name</code> type <code>string</code> as the default property. We also overwrote the included <code>id</code> property with a different type (by default it's a string).

            <p>Note: an ID property will <i>always</i> be created.</p>

            <h2 id="scaffolding">Scaffolding application tutorial</h2>
            <p>This will be a short tutorial as scaffolding will do almost everything for us, I won't go into detail on what it does as it will be covered in exstensive detail in the <a href="#resources">resources tutorial</a>. The source for this tutorial will be <a href="https://github.com/mde/geddy/tree/master/examples/todo_app">here</a>.</p>

            <p>First we'll create our application, this will create a base so we can start on.</p>
            <pre class="prettyprint">$ geddy app todo_app</pre>

            <p>Let's spend some time reviewing what geddy did. The previous command created a lot. During the tutorial we will edit and review some of this files, but we'll briefly explain what they are now so you get familiar with the base application.</p>

            <ul>
              <li><code>app/controllers</code>: contains the base controller and the main controller. All controllers will go in this folder</li>
              <li><code>app/views/layouts/application.html.ejs</code>: layout used by default by all the views</li>
              <li><code>app/views/main/index.html.ejs</code>: main view displayed when you visit the root of your web application</li>
              <li><code>config/development.js</code>: configuration for the development environment</li>
              <li><code>config/environment.js</code>: configuration for all your environments</li>
              <li><code>config/init.js</code>: this is where you write code that will be run only once your app starts.</li>
              <li><code>config/production.js</code>: configuration for the production environment</li>
              <li><code>config/router.js</code>: contains route settings. It has some examples and you can learn more about <a href="https://github.com/mde/geddy/wiki/Using-the-Router">routes from the Wiki.</a></li>
              <li><code>public/</code>: contains static assets that will be served directly by geddy's server </li>
              <li><code>public/css/</code>: Geddy uses <a href="http://twitter.github.com/bootstrap/">twitter bootstrap</a>. These are referenced by the layout file (<code>application.html.ejs</code>)</li>
              <li><code>public/img/</code>: contains a few images used by twitter bootstrap. Your images will usually go here as well</li>
              <li><code>public/js/</code>: bootstrap and jquery scripts</li>
            </ul>

            <p>Now from your app's root simply start geddy</p>

            <pre class="prettyprint">
$ cd todo_app
$ geddy</pre>
            
            <p>Then open your browser to <a href="http://localhost:4000/">localhost:4000</a>, and you'll find the hello world page.</p>

            <p>So now we want to create a scaffold to manage our todo items. We will create a title and status property so that we have some attributes to use.</p>
            <pre class="prettyprint">$ geddy scaffold todo title:default status</pre>

            <p>We are almost done. Now you have to restart geddy</p>
            <pre class="prettyprint">$ geddy</pre>

            <p>Open your browser to <a href="http://localhost:4000/todos">localhost:4000/todos</a> and you'll get a list of the todos which should be empty. Go ahead and look around, you can create show edit and delete todo items. We're going to make a few changes though.</p>

            <p>The first thing we'll do is to add some validation to our Todo model. So open 'app/models/todo.js' in your editor and add the following lines anywhere inside the constructor function</p>
            <pre class="prettyprint">
var Todo = function () {
...
  // Add this inside the constructor function
  this.validatesPresent('title');
  this.validatesLength('title', {min: 5});

  this.validatesWithFunction('status', function (status) {
    return status == 'open' || status == 'done';
  });
...
};
Todo = geddy.model.register('Todo', Todo);</pre>

            <p>Here we are making it so the title property is required and have a minumum of 5 characters. We also made it so the status acts like a boolean attribute but uses custom names instead of true/false. We should also change our <code>edit</code> and <code>add</code> views to limit the options, but we will do it as part of the <a href="#resources">resources tutorial</a>, for now we will leave the views the way they are.</p>
          
            <p>Now that we've made the needed changes, restart Geddy to update our model changes. Go and play with the app again, create a todo item, try to edit and test the validation rules. We've got a good todo application running and didn't really have to do much. Scaffolding is very good when you need something simple to get you started. To learn more about controllers and views keep reading and follow the <a href="#resources">resources tutorial</a>.</p>

            <h2 id="resources">Resource application tutorial</h2>

            <p>Let's start by using the <code>geddy</code> executable to generate a basic app-structure.</p>
            <pre class="prettyprint">$ geddy app todo_app</pre>

            <p>Now let's try out our new application by running geddy from your application's root</p>

            <pre class="prettyprint">
$ cd todo_app
$ geddy</pre>
            
            <p>Your app should be running on port 4000. Visit <a href="http://localhost:4000">http://localhost:4000</a> in your browser to see your app.</p>

            <h4>Optional: check out your app on a mobile phone</h4>
            <ul>
              <li>point your mobile phone's browser to your computer on port 4000</li>
              <li>OR open up your favorite phone simulator and go to <a href="http://localhost:4000">http://localhost:4000</a></li>
              <li>OR resize your browser to at least 480px wide</li>
            </ul>

            <h3>Generate a resource</h3>
            <p>Now, let's get started building our To Do list manager. First, we'll need to generate the <code>todo</code> resource. We do this using the <code>geddy</code> executable as well:</p>
            <pre class="prettyprint">$ geddy resource todo title:string status</pre>

            <p>What did that do?</p>
            <ul>
              <li>It generated a <code>todo</code> model including the given model properties</li>
              <li>It generated a <code>todos</code> controller</li>
              <li>It created a <code>todos</code> view directory. Please note the folder is empty since resource won't generate any views for you. </li>
              <li>It generated these routes from a resource route:
                <ul>
                  <li><code>/todos</code> (GET)</li>
                  <li><code>/todos</code> (POST)</li>
                  <li><code>/todos/add</code> (GET)</li>
                  <li><code>/todos/:id/edit</code> (GET)</li>
                  <li><code>/todos/:id</code> (GET)</li>
                  <li><code>/todos/:id</code> (PUT)</li>
                  <li><code>/todos/:id</code> (DELETE)</li>
                </ul>
              </li>
            </ul>

            <h3>Creating the Todo views</h3>
            <p>To start creating our views, create a few files in <code>app/views/todos</code>, those being:</p>
            <ul>
              <li><code>_form.html.ejs</code></li>
              <li><code>add.html.ejs</code></li>
              <li><code>edit.html.ejs</code></li>
              <li><code>index.html.ejs</code></li>
              <li><code>show.html.ejs</code></li>
            </ul>

            <p>We won't go into to much detail here, as it should be pretty self explanatory but I'll go through some things.</p>

            <p>First we'll create the <code>_form.html.ejs</code> partial template, this will hold all the form data for edit and add actions
              .</p>
            <pre class="prettyprint">
&lt;%
  var isUpdate = params.action == 'edit'
    , formTitle = isUpdate ? 'Update this To Do Item' : 'Create a new To Do Item'
    , action = isUpdate ? todoPath(params.id) + '?_method=PUT' : todosPath
    , deleteAction = isUpdate ? todoPath(params.id) + '?_method=DELETE' : ''
    , btnText = isUpdate ? 'Update' : 'Add'
    , doneSelectAttributes = isUpdate && todo.status === 'done' ? "selected=true" : ''
    , openSelectAttributes = isUpdate && todo.status === 'open' ? "selected=true" : ''
    , titleValue = isUpdate ? todo.title : ''
    , errors = params.errors;
%&gt;
&lt;form id="todo-form" class="form-horizontal" action="&lt;%= action %&gt;" method="POST"&gt;
  &lt;fieldset&gt;
    &lt;legend&gt;&lt;%= formTitle %&gt;&lt;/legend&gt;
    &lt;div class="control-group"&gt;
      &lt;label for="title" class="control-label"&gt;Title&lt;/label&gt;
      &lt;div class="controls"&gt;
        &lt;%- contentTag('input', titleValue, {type:'text', class:'span6', placeholder:'enter title', name:'title'}) %&gt;
        &lt;% if (errors) { %&gt;
          &lt;p&gt;
          &lt;% for (var p in errors) { %&gt;
            &lt;div&gt;&lt;%= errors[p]; %&gt;&lt;/div&gt;
          &lt;% } %&gt;
          &lt;/p&gt;
        &lt;% } %&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;% if (isUpdate) { %&gt;
      &lt;div class="control-group"&gt;
        &lt;label for="status" class="control-label"&gt;Status&lt;/label&gt;
        &lt;div class="controls"&gt;
          &lt;select name="status" class="span6"&gt;
            &lt;option &lt;%=openSelectAttributes%&gt;&gt;open&lt;/option&gt;
            &lt;option &lt;%=doneSelectAttributes%&gt;&gt;done&lt;/option&gt;
          &lt;/select&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;% } %&gt;
    &lt;div class="form-actions"&gt;
      &lt;%- contentTag('input', btnText, {type: 'submit', class: 'btn btn-primary'}) %&gt;
      &lt;% if (isUpdate) { %&gt;
        &lt;%- contentTag('button', 'Remove', {type: 'submit', formaction: deleteAction, formmethod: 'POST', class: 'btn btn-danger'}) %&gt;
      &lt;% } %&gt;
    &lt;/div&gt;
  &lt;/fieldset&gt;
&lt;/form&gt;</pre>

            <p>Here we created a couple variables so we can tell if it's for a edit or add action, then if we have any errors we dislay them. Also we are using a couple view helpers (contentTag) which are helpful with dealing with assets, links, etc. You can read more about our view helpers <a href="https://github.com/mde/geddy/wiki/View-Helpers">here</a>.</p>

            <p>Now that we've created a base for our add and edit actions, we'll do them now. They're simple they just use the _form partial. Add the following code to <code>add.html.ejs</code></p>
            <pre class="prettyprint">
&lt;div class="hero-unit"&gt;
  &lt;%= partial('_form', {params: params}); %&gt;
&lt;/div&gt;</pre>

            <p>The edit view is slightly different because we will need to pass the todo object to the partial. Modify <code>app/views/todos/edit.html.ejs</code> with the following code:</p>

            <pre class="prettyprint">
&lt;div class="hero-unit"&gt;
  &lt;%= partial('_form', {params: params, todo: todo}); %&gt;
&lt;/div&gt;</pre>

            <p>Now that we have views that will create todo items let's add a simple <code>show.html.ejs</code> just so we can test everything end to end. In the following code I just loop through the params.</p>

            <pre class="prettyprint">
&lt;div class="hero-unit"&gt;
  &lt;%- linkTo('Edit this todo', editTodoPath(params.id), {class: 'btn pull-right'}); %&gt;
  &lt;h3&gt;Params&lt;/h3&gt;
  &lt;ul&gt;
  &lt;% for (var p in todo) { %&gt;
    &lt;li&gt;&lt;%= p + ': ' + params[p]; %&gt;&lt;/li&gt;
  &lt;% } %&gt;
  &lt;/ul&gt;
&lt;/div&gt;</pre>
            
            <p>Finally we need to create the index action to link everything together.</p>
            <pre class="prettyprint">
&lt;div class="hero-unit"&gt;
  &lt;h2&gt;To Do List&lt;/h2&gt;
  &lt;%- linkTo('Create a new To Do', addTodoPath, {class: 'btn pull-right'}) %&gt;
&lt;/div&gt;
&lt;% if (todos && todos.length) { %&gt;
  &lt;% for (var i in todos) { %&gt;
  &lt;div class="row todo-item"&gt;
    &lt;div class="span8"&gt;
        &lt;h3&gt;&lt;%- linkTo(todos[i].title, todoPath(todos[i].id)) %&gt;&lt;/h3&gt;
    &lt;/div&gt;
    &lt;div class="span4"&gt;&lt;h3&gt;&lt;i class="icon-list-alt"&gt;&lt;/i&gt;&lt;%= todos[i].status; %&gt;&lt;/h3&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;% } %&gt;
&lt;% } %&gt;</pre>

            <p>For the index action we just have a link to add new items, and a list of all the items, with a link to each of their edit paths. If you notice we're using special helpers here, that create links to the path specified.</p>

            <h3>The Todo model</h3>
            <p>We're ready to start in on modeling our data. Geddy provides us with some pretty cool tools to do this:</p>
            <ul>
              <li>Validation</li>
              <li>Typed Data</li>
              <li>Instance Methods</li>
              <li>Static Methods</li>
            </ul>
            <p>These tools should look somewhat familiar to anyone who's used an ORM-system like Ruby's ActiveRecord, or DataMapper.</p>

            <p>Go ahead and open up <code>app/models/todo.js</code>. Read through the commented out code there for some ideas on what you can do with models. We'll be writing our model from scratch for this tutorial, so let's leave that commented out.</p>

            <p>So, minus the commented out code, you should have a file that looks like this:</p>
            <pre class="prettyprint">
var Todo = function () {

  this.defineProperties({
      title: {type: 'string'}
    , status: {type: 'string'}
  });

};

Todo = geddy.model.register('Todo', Todo);</pre>

            <p>The <code>defineProperties</code> method takes any number of properties to be added to the model. The keys in the object will be added as properties on the model. The values are just objects that describe the properties. When we ran the scaffold command it created these for us. But we want to change it so they are all `required`. To learn more, check out the <a href="https://github.com/mde/geddy/blob/master/README.md">readme</a>.</p>

            <p>There's also a more detailed validation API. While we're here, let's add some validation as well. The final code should look like this:</p>

            <pre class="prettyprint">
var Todo = function () {

  this.defineProperties({
      title: {type: 'string'}
    , status: {type: 'string'}
  });
  
  this.validatesPresent('title');
  this.validatesLength('title', {min: 5});

  this.validatesWithFunction('status', function (status) {
    return status == 'open' || status == 'done';
  });
};

Todo = geddy.model.register('Todo', Todo);</pre>

            <p>For the <code>title</code> property, we made sure that the property is always present and we made sure that the <code>title</code> property is a minimum of 5 characters long.</p>

            <p>For the <code>status</code> property, we used a function to validate that the property is always set to either <code>open</code> or <code>done</code>.</p>

            <p>For more information about Geddy's Models, you can check out the <a href="https://github.com/mde/geddy/wiki/Models">Model wiki page</a>.</p>

            <h3>The Todo model-adapter</h3>

            <p>Now that we've set up our <code>todo</code> model, we need to define a way to store it. To keep our models persistance agnostic, Geddy uses model-adapters. By default it will store objects in memory using the <code>memory</code> model adapter. You can change the default memoryAdapter in <code>config/development.js</code>.

            <pre class="prettyprint">defaultAdapter = 'memory'</pre>

            <p>Now we've got a place to store our <code>todo</code>'s. This is in your application's memory, so it will disappear when you restart the server.</p>

            <h4>Optional: use mongo for persistence </h4>
            <p>Install a <a href="http://www.mongodb.org/downloads">mongodb</a> server if you haven't already and <code> $ [sudo] npm install -g mongodb-wrapper</code> to install the required mongodb-wrapper and set <code>defaultAdapter = 'mongo'</code> in config/development.js instead of the memory adapter. You will also have to specify the db configuration <code>db: { mongo: { dbname: 'model_test' }</code>. For more information see the <a href="https://github.com/mde/geddy/wiki/Model-Adapters">Model Adapter Wiki Page</a></p>

            <h3>The Todo Controller</h3>
            <p>Controllers sit between the views and models. They are also the entry point of our code. When a user gets a page a function in a controller, also called a controller acton, will get invoked. The controller will usually interact with the model and pass it to the view. The pattern isn't as black and white, but for the purpose of the tutorial, let's move on to actually write some controller actions.</p>

            <h4 id="saving-todos">Saving todos</h4>

            <p>To save a todo we need to edit the <code>create</code> action in <code>app/controllers/todos.js</code>. It's not doing much at the momment so lets modify it a little bit.</p>

            <pre class="prettyprint">
this.create = function (req, resp, params) {
  var self = this
    , todo = geddy.model.Todo.create({title:params.title, status:'open'});

  todo.save(function(err, data) {
    if (err) {
      params.errors = err;
      self.transfer('add');
    } else {
      self.redirect({controller: self.name});
    }
  });
};</pre>

            <p>First, we create a new instance of the <code>Todo</code> model with <code>geddy.model.Todo.create</code>, passing in the title that our form will post up to us, and setting up the default status.</p>

            <p>Then we call we call the <code>save</code> method. Internally, save does two things. It validates the model based on the rules we defined earlier. This is similar to calling <code>todo.isValid()</code>. If the model was valid, it will delegate to the model adapter configured previously to actually persist the model. If either step fails, you will get an error collection as the first parameter of the function and we redirect the user back to the /todos/add route. Otherwise we redirect to the controller's default action <code>self.redirect({controller: self.name});</code>.</p>

            <h4 id="list-todos">Listing all todos</h4>

            <p>Now that we we can create To Do items, we should probably list them somewhere. Lets change the <code>index</code> action in the <code>todos</code> controller.</p>

            <p>Open up <code>/app/controllers/todos.js</code> again and replace the current implementaton with the following code.</p>

            <pre class="prettyprint">
this.index = function (req, resp, params) {
  var self = this;

  geddy.model.Todo.all(function(err, todos) {
    self.respond({params: params, todos: todos});
  });
};</pre>

            <p>This part is a bit simpler and it follows a similar pattern. Instead of calling create in <code>geddy.model.Todo</code> this time we simply call <code>all</code> and we pass the data back to the view for rendering</p>

            <p>Now that we can can load todo items you can test it by starting up Geddy and going to <a href="http://localhost:4000/todos">localhost:4000/todos</a> and you can view the list of items.</p>

            <h4 id="show-todo">Showing a todo</h4>

            <p>Now that we have our index action working as expected, we should work on the <code>show</code> controller action to display todo details.</p>

            <pre class="prettyprint">
this.show = function (req, resp, params) {
  var self = this;

  geddy.model.Todo.load(params.id, function(err, todo) {
    self.respond({params: params, todo: todo});
  });
};</pre>
            <p>Now we have a working show action in the controller to load items.</p>

            <h4 id="update-todo">Updating a todo</h4>

            <p>Alright, now that we can view our todos let's edit the <code>update</code> and <code>edit</code> actions in the <code>todos</code> controller. They should look something like this:</p>

            <pre class="prettyprint">
this.edit = function (req, resp, params) {
  var self = this;

  geddy.model.Todo.load(params.id, function(err, todo) {
    self.respond({params: params, todo: todo});
  });
};

this.update = function (req, resp, params) {
  var self = this;

  geddy.model.Todo.load(params.id, function(err, todo) {
    todo.updateAttributes(params);

    todo.save(function(err, data) {
      if (err) {
        params.errors = err;
        self.transfer('edit');
      } else {
        self.redirect({controller: self.name});
      }
    });
  });
};</pre>

            <h3 id="delete-todo">Deleting a todo</h3>

            <p>The delete is really simple specially now that you're familiar with the pattern. This time you will have to call remove passing the id of the todo you want to delete. We will leave the details as an excercise. Remember that you can always compare your solution to the <a href="https://github.com/mde/geddy/tree/master/examples/todo_app">final version</a>.</p>
            
            <h3 id="conclusion">Conclusion</h3>

            <p>At this point you should have a working To Do List app!</p>

            <h3>Oh, did we mention that you have a JSON and JSONP api now too?</h3>
            <p>Check it out:</p>
            <ul>
              <li>GET: <code>/todos.json</code></li>
              <li>GET: <code>/todos/:id.json</code></li>
              <li>POST: <code>/todos</code></li>
              <li>PUT: <code>/todos/:id</code></li>
            </ul>

            <p>If you want to explore a little more, here are some other things you could do:</p>

            <ul>
              <li>Change the <code>Main#index</code> route to point to the <code>Todos#index</code> action (hint, check out <code>config/router.js</code>)</li>
              <li>Add some logging with <code>geddy.log</code></li>
              <!-- Removed this item because metrics isn't working-->
              <!--<li>Set up metrics by running <code>npm install metrics</code>, and uncomment the metrics entry (<code>metrics: { port: 4001 }</code>) in your <code>config/environment.js</code> file</li>-->
              <li>Configure mongo, riak or postgress and use it instead of the memory modelAdapter. See how easy it's to switch</li>
            </ul>

          </div>
        </div>
      </div>

      <footer>
        <p>&copy; GeddyJS.org 2112</p>
      </footer>

    </div> <!-- /container -->

    <!--TODO: Add scripts back<script>
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-5555148-4']);
_gaq.push(['_setDomainName', '.geddyjs.org']);
_gaq.push(['_trackPageview']);

(function () {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>-->

  </body>
</html>
Something went wrong with that request. Please try again.