Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Updated Tutorial #203

Merged
merged 16 commits into from

4 participants

Miguel Madero Kieran Huggins Matthew Eernisse Larz Conwell
Miguel Madero

There was a lot of yak shaving involved. I'm new with node, jake and the like so I had to do a lot of unrelated digging and fixed (or will log) a few bugs that I found along the way.

Please have a look and let me know what do you think, specially of the changes made to the templates, cli and other areas.

I also ended up with a long list of 'todos' that I'm not sure if I should log as issues or where would be the best place to discuss them. I'm pasting them here to start the discussion instead of just flooding the issue list.

Bugs:

  • "host/controller/" doesn't work as "host/controller" when using routes
  • Metrics isn't working (fails when starting geddy)
  • Geddy (server) fails without warning if there's another server running on 4000. I think it should crash or at least show a warning and move to a different port (only in dev)
  • If we have spaces when calling geddy jake fails because in cli.js we're calling cmds.split(' '). This is common when we have more than one property when calling scaffold, resource or model.
  • If the generator fails midway, there's no indication of th error (I have an inprogress fix calling jake differently to listen the error event and WARN the user and ask them to use the -d flag for more details)
  • It looks like if we change a rule in the model it affects the way we retrieve old date. For exmaple, I saved a TODO with a short title, then add a rule {min: 5} and the title of old TODOs is empty. There's no easy way to retrieve and compare using Geddy so that someone can fix the old, now invalid, TODOs.
  • Why does the mongodb-wrapper has to be there as a LOCAL module. Could it be globally installed?
  • If no default property is given Geddy will use id as the display property. I think we should pick the first property instead of id which is rarely useful. Ids should be internal and using it as a the default display property is misleading, I think Geddy should strive to use good defaults or force them to be explicit.

To re-test again with the HEAD

  • Review this issue and update the documentation once it's fixed. #79
    • The ajax PUT returns 302 to 'todos' and that returns 405 possibly others

I'm happy to follow this up. I just wanted to start wrapping the tutorial first and to start getting some input in some of the other things I found.

Kieran Huggins
Owner
Matthew Eernisse
Owner
mde commented

That stupid change to DOS endings (my bad for actually fixing a bug inside Windows) has fucked up the ability to merge this, since it means the entire file has changed. I just pushed the change back to Unix, so you'll have an interesting pull when you sync from master. Lesson learned -- make sure Windows Vim converts back to Unix.

Also, do you want to file issues for all these bugs listed? Then we can discuss them individually.

Matthew Eernisse
Owner
mde commented

Oh, and I should say -- really kick-ass work on this!

Matthew Eernisse
Owner
mde commented

@kieran, I agree, I can't imagine a case where the trailing slash should actually be significant. Do you want to patch that? You do have commit access! :P If you don't get to it, I'll fix it. :)

Miguel Madero

@kieran and @mde I added a separate issue to discuss the trailing slash.
I'll add issues for the rest of the list as well.

@mde I fixed the DOS endings issue already so I had no problems with the merge.

Matthew Eernisse mde merged commit f91fe7b into from
Matthew Eernisse
Owner
mde commented

This looks good. Since our amazing new Web site update is almost ready, I'm going to wait until that lands to push this release and start talking it up. Now all the pressure is on you, @Techwraith!

Larz Conwell

:+1: x 1000 Nice man!

Miguel Madero

@mde there're a few minor changes that would be nice to have before the next release. Could you have a look at #202

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 29, 2012
  1. Miguel Madero

    Initial changes

    MiguelMadero authored
  2. Miguel Madero

    Changed references to 'Mongo' for 'mongo' in docos because it doesn't…

    MiguelMadero authored
    … work with uppercase. We should probably make it case insensitive
  3. Miguel Madero

    Makes the memory adapter the default in config instead of adding it t…

    MiguelMadero authored
    …o the models each time. This way we don't have to edit our models after using the generators. Later we might add a switch to generator to specify a model-specific adapter
  4. Miguel Madero
  5. Miguel Madero
Commits on Sep 30, 2012
  1. Miguel Madero
  2. Miguel Madero
  3. Miguel Madero

    Adds quick install

    MiguelMadero authored
  4. Miguel Madero
Commits on Oct 1, 2012
  1. Miguel Madero
  2. Miguel Madero

    Made memory the defaultAdapter because the generator fails if we have…

    MiguelMadero authored
    … mongo and it's not installed as a local module. Memory has less friction when starting up
  3. Miguel Madero

    Removed some TODOs

    MiguelMadero authored
  4. Miguel Madero
Commits on Oct 3, 2012
  1. Miguel Madero
  2. Miguel Madero
  3. Miguel Madero
This page is out of date. Refresh to see the latest.
14 Makefile
View
@@ -27,9 +27,17 @@ build:
install:
@mkdir -p $(DESTDIR)$(PREFIX)/bin && \
- mkdir -p $(DESTDIR)$(PREFIX)/lib/node_modules/geddy && \
- mkdir -p ./node_modules && \
- npm install jake utilities model barista && \
+ mkdir -p $(DESTDIR)$(PREFIX)/lib/node_modules/geddy && \
+ mkdir -p ./node_modules && \
+ npm install jake utilities model barista && \
+ cp -R ./* $(DESTDIR)$(PREFIX)/lib/node_modules/geddy/ && \
+ ln -snf ../lib/node_modules/geddy/bin/cli.js $(DESTDIR)$(PREFIX)/bin/geddy && \
+ chmod 755 $(DESTDIR)$(PREFIX)/lib/node_modules/geddy/bin/cli.js && \
+ echo 'Geddy installed.'
+
+quickinstall:
+ @mkdir -p $(DESTDIR)$(PREFIX)/bin && \
+ mkdir -p $(DESTDIR)$(PREFIX)/lib/node_modules/geddy && \
cp -R ./* $(DESTDIR)$(PREFIX)/lib/node_modules/geddy/ && \
ln -snf ../lib/node_modules/geddy/bin/cli.js $(DESTDIR)$(PREFIX)/bin/geddy && \
chmod 755 $(DESTDIR)$(PREFIX)/lib/node_modules/geddy/bin/cli.js && \
2  examples/related_models/app/models/box.js
View
@@ -6,7 +6,7 @@ var Box = function () {
this.hasMany('Things');
- this.adapter = 'Mongo';
+ this.adapter = 'mongo';
};
Box = geddy.model.register('Box', Box);
2  examples/related_models/app/models/thing.js
View
@@ -7,7 +7,7 @@ var Thing = function () {
this.belongsTo('Box');
- this.adapter = 'Mongo';
+ this.adapter = 'mongo';
};
Thing = geddy.model.register('Thing', Thing);
2  examples/related_models/app/models/widget.js
View
@@ -6,7 +6,7 @@ var Widget = function () {
this.hasOne('Thing');
- this.adapter = 'Mongo';
+ this.adapter = 'mongo';
};
Widget = geddy.model.register('Widget', Widget);
2  examples/todo_app_coffee/app/models/todo.coffee
View
@@ -16,6 +16,6 @@ Todo = ->
@validatesWithFunction 'status', (status) ->
status == 'open' || status == 'done'
- @adapter = 'Mongo'
+ @adapter = 'mongo'
Todo = geddy.model.register 'Todo', Todo
534 site/tutorial.html
View
@@ -13,7 +13,8 @@
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+ <!--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">
@@ -97,7 +98,8 @@
<link rel="apple-touch-icon" sizes="114x114" href="images/apple-touch-icon-114x114.png">
</head>
- <body style="background-image: url(http://subtlepatterns.com/patterns/whitey.png); background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-position: initial initial; background-repeat: initial initial; " onload="prettyPrint()">
+ <!-- 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">
@@ -149,15 +151,14 @@
<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. There will be two created applications one created from scaffolding(<a href="https://github.com/mde/geddy/tree/master/examples/todo_app_mongo">Finished version</a>) and one created from using resources(<a href="https://github.com/mde/geddy/tree/master/examples/todo_app">Finished version</a>).</p>
+
+ <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 the base application</li>
+ <li>Creating a Geddy application</li>
<li>Learning how to use the Geddy executable</li>
- <li>Setting up RESTful routes for our app</li>
<li>Using Geddy models</li>
- <li>How to use init.js in your applications startup</li>
<li>How views in Geddy work</li>
<li>How to use controllers to tie everything together</li>
</ul>
@@ -168,11 +169,12 @@ <h2 id="installing">Installing Geddy</h2>
<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>
- <blockquote class="pull-right">(Note installing packages globally may require super-user access)</blockquote>
+ <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 it's 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>
+ <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>
@@ -191,114 +193,132 @@ <h2 id="executable">Using the Geddy command</h2>
<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 and a default model adapter</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>). Here we'll learn how to use those commands.</p>
+ <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 a 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>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 <a href="#model-properties">here</a>. This will create a new model including the model properties given.</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. We won't go over model properties right now but you can learn about them <a href="#model-properties">here</a>. This will create a controller, a model including the given model properties and a resource route.</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. We won't go over model properties right now but you can learn about them <a href="#model-properties">here</a>. 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>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 couple commands(<code>resource</code>, <code>model</code> and <code>scaffold</code>) that also include a model properties argument. This is a list seperated by spaces that include the property, it's type and an optional default setting. Below are some examples of how they are used in the commands.</p>
+ <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 example will create our normal scaffolding and include a <code>name</code> option that's a <code>string</code> type. If no type is given it will default to <code>string</code>.</p>
+ <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 written it <code>name:string:default</code>, or you could've used a different type of course. the <code>default</code> setting also includes a alias called <code>def</code>, if no default property is given it will use <code>id</code> as the default.</p>
+ <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:number</pre>
- <p>As the above examples this creates are scaffold, and this time we use <code>name</code> type <code>string</code> as the default property we also overwrite the included <code>id</code> property. If no id property is given Geddy will use include <code>id</code> type <code>string</code></p>
+ <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).
- <blockquote class="pull-right">(Note a ID property will <i>always</i> be created)</blockquote>
+ <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</a> tutorial. The source for this tutorial will be <a href="https://github.com/mde/geddy/tree/master/examples/todo_app_mongo">here</a></p>
+ <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>Now you can start the application up by simply doing <code>$ cd todo_app && geddy</code>, Then open your browser to localhost:4000, and you'll find the hello world page.</p>
+ <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>
- <p>So now we want to create a scaffold that will be used to create 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 status</pre>
+ <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>
- <p>Now that we've created a scaffolding we should install the mondodb-wrapper package and install a <a href="http://www.mongodb.org/downloads">mongodb</a> server if you haven't already. This is because scaffolding will create a default model adapater for us that uses mongodb.</p>
- <pre class="prettyprint">$ [sudo] npm install -g mongodb-wrapper</pre>
- <p>Once that gets installed and we start our mongodb server up we can start up Geddy to test our application. <code>$ geddy</code></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>Open your browser to localhost:4000/todos 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>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>The first thing we'll do it edit the model some so open 'app/models/todo.js' in your editor, and make these changes.</p>
- <pre class="prettyprint">
-...
-this.defineProperties({
- id: {type: 'string', required: true}
- , title: {type: 'string', required: true}
- , status: {type: 'string', required: true}
-});
-
-this.validatesPresent('title');
-this.validatesLength('title', {min: 5});
-
-this.validatesWithFunction('status', function (status) {
- return status == 'open' || status == 'done';
-});
-...
- </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. Now we'll need to edit the edit and add views to reflect the status changes.</p>
+ <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 () {
...
-&lt;label for="status"&gt;status&lt;/label&gt;
-&lt;div class="controls"&gt;
- &lt;select name="status", class="span1"&gt;
- &lt;option&gt;open&lt;/option&gt;
- &lt;option&gt;done&lt;/option&gt;
- &lt;/select&gt;
-&lt;/div&gt;
+ // Add this inside the constructor function
+ this.validatesPresent('title');
+ this.validatesLength('title', {min: 5});
+
+ this.validatesWithFunction('status', function (status) {
+ return status == 'open' || status == 'done';
+ });
...
- </pre>
- <p>Now that we've made the needed changes, restart Geddy to update our model changes, now we've got a good todo application running and didn't really have to do anything. Scaffolding is very good when you don't need to do much. To learn more about models and applications keep reading and follow the <a href="#resources">resource</a> application tutorial</p>
+};
+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 doing <code>$ cd todo_app && geddy</code> command, 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>
+ <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>
+ <h4>Optional: check out your app on a mobile phone</h4>
<ul>
- <li>point your mobile phone's browser to your computer's port 4000</li>
+ <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, lets actually 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 name string</pre>
+ <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</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>
@@ -312,21 +332,20 @@ <h2 id="resources">Resource application tutorial</h2>
</li>
</ul>
- <p>Now lets restart Geddy so our changes are updated. <code>$ geddy</code> Once it starts up point your browser to <a href="http://localhost:4000/todos.json">http://localhost:4000/todos.json</a> to view the index action in JSON. We don't currently have any views but we're about to do that now.</p>
-
<h3>Creating the Todo views</h3>
- <p>To start creating our views, create a few files in 'app/views/todos', those being:</p>
+ <p>To start creating our views, create a few files in <code>app/views/todos</code>, those being:</p>
<ul>
- <li>_form.html.ejs</li>
- <li>add.html.ejs</li>
- <li>edit.html.ejs</li>
- <li>index.html.ejs</li>
- <li>show.html.ejs</li>
+ <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 _form partial template, this will hold all the form data for edit and add actions.</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'
@@ -334,7 +353,8 @@ <h2 id="resources">Resource application tutorial</h2>
, action = isUpdate ? todoPath(params.id) + '?_method=PUT' : todosPath
, deleteAction = isUpdate ? todoPath(params.id) + '?_method=DELETE' : ''
, btnText = isUpdate ? 'Update' : 'Add'
- , doneStatus = isUpdate ? 'checked' : ''
+ , doneSelectAttributes = isUpdate && todo.status === 'done' ? "selected=true" : ''
+ , openSelectAttributes = isUpdate && todo.status === 'open' ? "selected=true" : ''
, titleValue = isUpdate ? todo.title : ''
, errors = params.errors;
%&gt;
@@ -356,11 +376,11 @@ <h2 id="resources">Resource application tutorial</h2>
&lt;/div&gt;
&lt;% if (isUpdate) { %&gt;
&lt;div class="control-group"&gt;
- &lt;label for="status"&gt;Status&lt;/label&gt;
+ &lt;label for="status" class="control-label"&gt;Status&lt;/label&gt;
&lt;div class="controls"&gt;
- &lt;select name="status"&gt;
- &lt;option&gt;open&lt;/option&gt;
- &lt;option&gt;done&lt;/option&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;
@@ -372,31 +392,36 @@ <h2 id="resources">Resource application tutorial</h2>
&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>
+&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 sense they just use the _form partial</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>This template will be for both add and edit actions. We just create a partial from _form and include all the params.</p>
+&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>
- <p>Now that we have views that will create todo items let's create the show action so we can view the todo items we create.</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 params) { %&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>I will leave the show action to you for a exercise, but herre I just loop through the params and show them.</p>
-
+&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;
@@ -407,16 +432,16 @@ <h2 id="resources">Resource application tutorial</h2>
&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, editTodoPath(todos[i].id)) %&gt;&lt;/h3&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 ll 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>
+&lt;% } %&gt;</pre>
- <h3>Creating the Todo model</h3>
+ <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>
@@ -426,298 +451,153 @@ <h2 id="resources">Resource application tutorial</h2>
</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 lets leave that commented out. (It's been deleted in the example app.)</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({
- id: {type: 'string', required: true}
- , title: {type: 'string'}
+ title: {type: 'string'}
, status: {type: 'string'}
});
};
-Todo = geddy.model.register('Todo', Todo);
- </pre>
- <p>The `defineProperties` 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` so set `title` and `status` to match `id` now.</p>
+Todo = geddy.model.register('Todo', Todo);</pre>
- <p>To learn more, check out the <a href="https://github.com/mde/geddy/blob/master/README.md">readme</a>.</p>
+ <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 more detailed validation API. While we're here, lets use that API to set up some more validations:</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">
-this.validatesPresent('title');
-this.validatesLength('title', {min: 5});
-
-this.validatesWithFunction('status', function (status) {
- return status == 'open' || status == 'done';
-});
- </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 'status' 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>
-
- <h4>Creating a Todo model-adapter</h4>
-
- <p>Now that we've set up our <code>todo</code> model, we can create somewhere to store our models. For the purposes of this tutorial, we're just going to keep the data in memory. We'll hang a <code>todos</code> array off of our global <code>geddy</code> object to stick the data in. If you want to make this app more robust after the tutorial, you could write an adapter to put your data in a SQL database, or Redis, or even just write it to a text-file.</p>
-
- <h4>Editing your init.js file</h4>
-
- <p>Open up your <code>config/init.js</code> file. All that should be in there now is a global uncaught exception handler.</p>
+var Todo = function () {
- <pre class="prettyprint">
-if (geddy.config.environment != 'development') {
- process.addListener('uncaughtException', function (err) {
- geddy.log.error(JSON.stringify(err));
+ this.defineProperties({
+ title: {type: 'string'}
+ , status: {type: 'string'}
});
-}
- </pre>
-
- <p>Right after that block of code, lets hang our array off the <code>geddy</code> global:</p>
-
- <pre class="prettyprint">geddy.todos = [];</pre>
-
- <p>There, now we've got a place to store our <code>todo</code>'s. This is in your application-memory, so it will disappear when you restart the server.</p>
-
- <h4>Creating the model adapter</h3>
-
- <p>A model-adapter provides the basic CRUD methods a model needs. Our data source is pretty simple (just an array!), so writing our model adapter should be pretty simple too.</p>
+
+ this.validatesPresent('title');
+ this.validatesLength('title', {min: 5});
- <p>Create a directory in <code>lib</code> called <code>model_adapters</code></p>
-
- <pre class="prettyprint">$ mkdir lib/model_adapters</pre>
-
- <p>And create a file in <code>lib/model_adapters</code> called <code>todo.js</code></p>
-
- <pre class="prettyprint">$ touch lib/model_adapters/todo.js</pre>
-
- <p>Lets open up that file and add in some boilerplate code:</p>
-
- <pre class="prettyprint">
-var Todo = new (function () {
-})();
-exports.Todo = Todo;
- </pre>
-
- <h4>Require the model adapter in init.js</h4>
+ this.validatesWithFunction('status', function (status) {
+ return status == 'open' || status == 'done';
+ });
+};
- <p>So we set up a new <code>Todo</code> model-adapter object. It's pretty barren right now, but we'll get to that soon. For now, we'll have to go back to <code>init.js</code> and add some code so that it's loaded into our app when it starts up. After the <code>geddy.todos = [];</code> in <code>config/init.js</code> add these two lines:</p>
+Todo = geddy.model.register('Todo', Todo);</pre>
- <pre class="prettyprint">
-geddy.model.adapter = {};
-geddy.model.adapter.Todo = require(process.cwd() + '/lib/model_adapters/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>
- <blockquote class="pull-right">We're working on making this nicer.</blockquote>
+ <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>We created a blank model-adapter object, and add the <code>Todo</code> model adapter onto it.</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 id="saving-todos">Saving todos</h3>
+ <h3>The Todo model-adapter</h3>
- <p>Now that we have our model and model adapter in place, we can start in on the app logic. Lets start with adding to do items to our to do list.</p>
+ <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>.
- <h4>Edit the save method on the adapter to save a todo instance</h4>
+ <pre class="prettyprint">defaultAdapter = 'memory'</pre>
- <p>When working with data, the first place you should go is the model adapter. We need to be able to save an instance of our <code>Todo</code> model to our <code>geddy.todos</code> array. So open up <code>lib/model_adapters/todo.js</code> and add in a <code>save</code> method:</p>
+ <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>
- <pre class="prettyprint">
-this.save = function (todo) {
- todo.saved = true;
- geddy.todos.push(todo);
-};
- </pre>
+ <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>
- <p>All we have to do is set the instance's <code>saved</code> property to true and push the item into the <code>geddy.todos</code> array. Now lets move on to the controller <code>create</code> action.</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>Edit the create action to save a todo instance</h4>
+ <h4 id="saving-todos">Saving todos</h4>
- <p>Go ahead and take a look at the <code>create</code> action in <code>app/controllers/todos.js</code></p>
+ <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) {
- // Save the resource, then display index page
- this.redirect({controller: this.name});
-};
- </pre>
-
- <p>Pretty simple, right? It's stubbed it out for you. So let's modify it a little bit:</p>
-
- <pre class="prettyprint">
-this.create = function (req, resp, params) {
- var todo = geddy.model.Todo.create({title: params.title, id: geddy.string.uuid(10), status: 'open'});
- if (todo.isValid()) {
- todo.save();
- this.redirect({controller: this.name});
- } else {
- this.redirect({controller: this.name, action: 'add?error=true'});
- }
-};
- </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 defaults for the id and status.</p>
-
- <p>Then we check to see if the model passed validation, if it did, we call the <code>save</code> method that we created on the model adapter and redirect the user back to the <code>/todos</code> route. If it didn't pass validation, we redirect the user back to the </code>/todos/add</code> route and pass an error as a query parameter.</p>
-
- <p>Geddy has built-in sessions too, so this might be another good spot to improve your app after you finish the tutorial.</p>
+ 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>
- <h3 id="list-todos">Listing all todos</h3>
+ <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>Now that we have user input To Do items being added into our <code>geddy.todos</code> array, we should probably list them somewhere. Lets start in on the <code>index</code> action in the <code>todos</code> controller.</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>Edit the index action to show all todos</h4>
+ <h4 id="list-todos">Listing all todos</h4>
- <p>Open up <code>/app/controllers/todos.js</code> again and take a look at the <code>index</code> action. It should look something like this:</p>
+ <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>
- <pre class="prettyprint">
-this.index = function (req, resp, params) {
- this.respond({params: params});
-};
- </pre>
-
- <p>This part is really simple, just replace the <code>params</code> property in the template variable object with a <code>todos</code> property and set it to <code>geddy.todos</code>, to pass that list down into your view.</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) {
- this.respond({todos: geddy.todos});
-};
- </pre>
-
- <p>Now that we can can load todo items you can test it by starting up Geddy and go to <a href="http://localhost:4000/todos">http://localhost:4000/todos</a> and you can view the list of items.</p>
-
- <h3 id="show-todo">Showing a todo</h3>
-
- <p>Now that we have our index action working as expected, we should probably work on the <code>show</code> controller action.</p>
-
- <h4>Create a load method in the model adapter</h4>
- <p>Open up your model adapter again (<code>/lib/model_adapters/todo.js</code>) - by now, it should look something like this: </p>
- <pre class="prettyprint">
-var Todo = new (function () {
-
- this.save = function (todo) {
- todo.saved = true;
- geddy.todos.push(todo);
- };
-
-})();
-
-exports.Todo = Todo;
- </pre>
-
- <p>Lets define a <code>load</code> method in this adapter, for getting one of the todos from the list:</p>
- <pre class="prettyprint">
-var Todo = new (function () {
-
- this.load = function (id, callback) {
- for (var i in geddy.todos) {
- if (geddy.todos[i].id == id) {
- return callback(geddy.todos[i]);
- }
- }
- callback({});
- };
-
- this.save = function (todo) {
- todo.saved = true;
- geddy.todos.push(todo);
- };
-
-})();
-
-exports.Todo = Todo;
- </pre>
-
- <p>This <code>load</code> method takes an <code>id</code> and a <code>callback</code>. It loops through the items in <code>geddy.todos</code> and checks to see if the current item's <code>id</code> matches the passed in <code>id</code>. If it does, it calls the callback, passing the <code>todo</code> item back. If it doesn't find a match, it calls the callback with a blank object. Now we need to use this method in the <code>todos</code> controller's show action.</p>
+ var self = this;
- <p>This is a simple example that finds a single item by iterating the entire collection, but you could write an adapter that does a SQL-call to a database, or makes an API-call to a Web service.</p>
+ geddy.model.Todo.all(function(err, todos) {
+ self.respond({params: params, todos: todos});
+ });
+};</pre>
- <h4>Edit the show action to find a todo</h4>
+ <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>Open up your <code>todos</code> controller again and take a look at it's <code>show</code> action. It should look something like this:</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>
- <pre class="prettyprint">
-this.show = function (req, resp, params) {
- this.respond({params: params});
-};
- </pre>
+ <h4 id="show-todo">Showing a todo</h4>
- <p>Lets use the load method that we just created:</p>
+ <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.adapter.Todo.load(params.id, function (todo) {
- self.respond({todo: todo});
- });
-};
- </pre>
- <p>Now we have a working show action in the controller to load items from the list.</p>
- <h3 id="update-todo">Updating a todo</h3>
+ 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>Edit the save method in the model adapter to save over existing todos</h4>
+ <h4 id="update-todo">Updating a todo</h4>
- <p>Open up your model adapter again. We're going to want to change the save method to allow for saving over existing model instances. You're <code>save</code> method should look something like this:</p>
+ <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.save = function (todo, callback) {
- todo.saved = true;
- geddy.todos.push(todo);
-};
- </pre>
-
- <p>Lets edit it to look like this:</p>
-
- <pre class="prettyprint">
-this.save = function (todo, callback) {
- for (var i in geddy.todos) {
-
- // if it's already there, save it
- if (geddy.todos[i].id == todo.id) {
- geddy.todos[i] = todo;
- return;
- }
-
- }
- todo.saved = true;
- geddy.todos.push(todo);
+this.edit = function (req, resp, params) {
+ var self = this;
+ geddy.model.Todo.load(params.id, function(err, todo) {
+ self.respond({params: params, todo: todo});
+ });
};
- </pre>
- <p>This loops over all the <code>todo</code>'s in <code>geddy.todos</code> and if the id is already there, replace that <code>todo</code> with the new <code>todo</code> instance. If you were hooked up to a real DB here, you'd do a SQL UPDATE or similar here instead.</p>
-
- <h4>Edit the update action to find a todo, change the status, and save it</h4>
-
- <p>Alright, now that we have our <code>save</code> method in order, lets edit the <code>update</code> action in the <code>todos</code> controller. It should look something like this right now:</p>
-
- <pre class="prettyprint">
this.update = function (req, resp, params) {
- // Save the resource, then display the item page
- this.redirect({controller: this.name, id: params.id});
-};
- </pre>
+ var self = this;
- <p>You'll want to edit it to make it look like this:</p>
+ geddy.model.Todo.load(params.id, function(err, todo) {
+ todo.updateAttributes(params);
- <pre class="prettyprint">
-this.update = function (req, resp, params) {
- var self = this;
- geddy.model.adapter.Todo.load(params.id, function (todo) {
- todo.status = params.status;
- todo.save();
- self.redirect({controller: this.name, id: params.id});
+ todo.save(function(err, data) {
+ if (err) {
+ params.errors = err;
+ self.transfer('edit');
+ } else {
+ self.redirect({controller: self.name});
+ }
+ });
});
-};
- </pre>
+};</pre>
- <p>We're taking the id that we sent up via the ajax <code>PUT</code> request on the <code>show</code> page and using the <code>load</code> method that we created earlier to find a <code>todo</code> item. Then we're setting its <code>status</code> to be what we sent up in the params ('done'). Then we use the <code>save</code> method that we just updated to save over the existing <code>todo</code> item. Then, in case this isn't coming from an ajax request, we're redirecting the request over to the <code>show</code> action (hooray for progressive enhancment).</p>
+ <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>
@@ -734,9 +614,11 @@ <h3 id="conclusion">Conclusion</h3>
<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>
- <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>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>
@@ -749,7 +631,7 @@ <h3 id="conclusion">Conclusion</h3>
</div> <!-- /container -->
- <script>
+ <!--TODO: Add scripts back<script>
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-5555148-4']);
_gaq.push(['_setDomainName', '.geddyjs.org']);
@@ -760,7 +642,7 @@ <h3 id="conclusion">Conclusion</h3>
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>
+ </script>-->
</body>
</html>
3  templates/base/development.js
View
@@ -21,6 +21,9 @@ var config = {
, debug: true
, hostname: null
, port: 4000
+, model: {
+ defaultAdapter: 'memory'
+ }
, sessions: {
store: 'memory'
, key: 'sid'
10 templates/base/production.js
View
@@ -20,6 +20,16 @@ var config = {
detailedErrors: false
, hostname: null
, port: 4000
+/* TODO: Define a defaultAdapter. You can use postgresdb, memory, mongo or riak.
+, model: {
+ defaultAdapter: 'mongo'
+ }
+, db: {
+ mongo: {
+ dbname: 'local'
+ }
+ }
+ */
, sessions: {
store: 'cookie'
, key: 'sid'
2  templates/resource/model.ejs
View
@@ -13,8 +13,6 @@ var <%= names.constructor.singular %> = function () {
<% } -%>
});
- this.adapter = "memory";
-
/*
this.property('login', 'string', {required: true});
this.property('password', 'string', {required: true});
1  templates/scaffold/model.ejs
View
@@ -18,7 +18,6 @@ var <%= names.constructor.singular %> = function () {
this.autoIncrementId = true;
<% } -%>
<% } -%>
- this.adapter = 'memory';
/*
this.property('login', 'string', {required: true});
Something went wrong with that request. Please try again.