You are on page 1of 38

geddy

homedocumentationtutorialchangelogcommunityfaq

Quick start tutorial


Introduction Installation With scaffolding Without scaffolding Resource Views Model Controller API Conclusion

Introduction
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 finished version. In this tutorial we'll cover: Creating a Geddy application Learning how to use the Geddy executable Using Geddy models How views in Geddy work How to use controllers to tie everything together

Installation
If you haven't already, install Node on your machine. Next, install Geddy from NPM, this will also install Jake:
$ sudo npm install -g geddy

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.) Using the geddy gen command Now that we have Geddy installed we need to learn how to use its generator commands from the CLI. If no commands are given, Geddy will start up the server (if you're inside a Geddy application -- otherwise it will show the help dialog). But if you give Geddy the gen command, it can be used to create applications or resources for applications.

geddy gen commands: app <name>: Create a new Geddy application resource <name> [model attributes]: Create a new Geddy resource. Resources include a model, controller and a route scaffold <name> [model attributes]: Creates a new Geddy scaffolding. Scaffolding includes everything Resources have as well as views secret: Generate a new application secret in `config/environment` controller <name>: Generate a new controller including an index view and a route model <name> [model attributes]: Generate a new model console: opens a console in the context of geddy Options: --swig: When generating views, use Swig templates(Default: EJS) --jade, -j: When generating views, use Jade templates(Default: EJS) --handle, -H: When generating views, use Handlebars templates (Default: EJS) --mustache, -m: When generating views, use Mustache templates (Default: EJS)

How to use Geddy's generator commands Each of Geddy's generator commands (e.g., app, resource, controller, etc.) takes an or set of arguments (excluding secret and console). Here we'll learn how to use those. app 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. secret doesn't take any arguments, it will find your config/environment file and create a new application secret in it, deleting any other secret. controller 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 --swig, --jade, --handle or --mustache you can substitute the template language to your liking. model 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. resource 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. scaffold 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 --swig, --jade, --handle or --mustache you can substitute the template language to your liking. Model properties There are a three commands (resource, model and scaffold) 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.
$ geddy gen scaffold user name:string

The example above will create our normal scaffolding and include a name property of type string. If no type is given it will default to string.

$ geddy gen scaffold user name:default

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

This time we used name type string as the default property. We also overwrote the included id property with a different type (by default it's a string). Note: an ID property will always be created.

With scaffolding
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 resources tutorial. The source for this tutorial can be found here. First we'll create our application, this will create a base so we can start on.
$ geddy gen app todo_app

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 these files, but we'll briefly explain what they are now so you get familiar with the base application. app/controllers: contains the base controller and the main controller. All controllers will go in this folder app/views/layouts/application.html.ejs: layout used by default by all the views app/views/main/index.html.ejs: main view displayed when you visit the root of your web application config/development.js: configuration for the development environment config/environment.js: configuration for all your environments config/init.js: this is where you write code that will be run only once your app starts. config/production.js: configuration for the production environment config/router.js: contains route settings. It has some examples and you can learn more about routes from the Wiki. public/: contains static assets that will be served directly by geddy's server public/css/: Geddy uses twitter bootstrap. These are referenced by the layout file (application.html.ejs) public/img/: contains a few images used by twitter bootstrap. Your images will usually go here as well public/js/: bootstrap and jquery scripts Now from your app's root simply start geddy
$ cd todo_app $ geddy

Then open your browser and navigate to localhost:4000, and you'll find the hello world page. 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.


$ geddy gen scaffold todo title:default status

We are almost done. Now you have to restart geddy


$ geddy

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. 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
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);

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 edit and add views to limit the options, but we will do it as part of the resources tutorial, for now we will leave the views the way they are. 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 resources tutorial.

Without scaffolding
Let's start by using the geddy gen command to generate a basic app-structure.
$ geddy gen app todo_app

Now let's try out our new application by running Geddy from your application's root
$ cd todo_app $ geddy

Your app should be running on port 4000. Visit http://localhost:4000 in your browser to see your app. Optional: check out your app on a mobile phone Open up your favorite phone simulator and go to http://localhost:4000 OR resize your browser to at most 480px wide OR set your app to listen on an external IP address and use your actual phone

Resource
Now, let's get started building our To Do list manager. First, we'll need to generate the todo resource. We do this using the geddy gen command as well:
$ geddy gen resource todo title:string status

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

Views
To start creating our views, create a few files in app/views/todos, those being: _form.html.ejs add.html.ejs edit.html.ejs index.html.ejs show.html.ejs

We won't go into to much detail here, as it should be pretty self-explanatory but I'll go through some things. First we'll create the _form.html.ejs partial template, this will hold all the form data for edit and add actions .
<% 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; %> <form id="todo-form" class="form-horizontal" action="<%= action %>" method="POST"> <fieldset> <legend><%= formTitle %></legend> <div class="control-group"> <label for="title" class="control-label">Title</label>

<div class="controls"> <%- contentTag('input', titleValue, {type:'text', class:'span6', placeholder:'enter title', name:'title'}) %> <% if (errors) { %> <p> <% for (var p in errors) { %> <div><%= errors[p]; %></div> <% } %> </p> <% } %> </div> </div> <% if (isUpdate) { %> <div class="control-group"> <label for="status" class="control-label">Status</label> <div class="controls"> <select name="status" class="span6"> <option <%=openSelectAttributes%>>open</option> <option <%=doneSelectAttributes%>>done</option> </select> </div> </div> <% } %> <div class="form-actions"> <%- contentTag('input', btnText, {type: 'submit', class: 'btn btnprimary'}) %> <% if (isUpdate) { %> <%- contentTag('button', 'Remove', {type: 'submit', formaction: deleteAction, formmethod: 'POST', class: 'btn btn-danger'}) %> <% } %> </div> </fieldset> </form>

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 here. 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 add.html.ejs
<div class="hero-unit"> <%= partial('_form', {params: params}); %> </div>

The edit view is slightly different because we will need to pass the todo object to the partial. Modify app/views/todos/edit.html.ejs with the following code:
<div class="hero-unit"> <%= partial('_form', {params: params, todo: todo}); %> </div>

Now that we have views that will create todo items let's add a simple show.html.ejs just so we can test everything end to end. In the following code I just loop through the params.
<div class="hero-unit"> <%- linkTo('Edit this todo', editTodoPath(params.id), {class: 'btn pullright'}); %> <h3>Params</h3> <ul> <% for (var p in todo) { %> <li><%= p + ': ' + params[p]; %></li>

<% } %> </ul> </div>

Finally we need to create the index action to link everything together.


<div class="hero-unit"> <h2>To Do List</h2> <%- linkTo('Create a new To Do', addTodoPath, {class: 'btn pull-right'}) %> </div> <% if (todos && todos.length) { %> <% for (var i in todos) { %> <div class="row todo-item"> <div class="span8"> <h3><%- linkTo(todos[i].title, todoPath(todos[i].id)) %></h3> </div> <div class="span4"><h3><i class="icon-list-alt"></i><%= todos[i].status; %></h3></div> </div> <% } %> <% } %>

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.

Model
We're ready to start in on modeling our data. Geddy provides us with some pretty cool tools to do this: Validation Typed Data Instance Methods Static Methods

These tools should look somewhat familiar to anyone who's used an ORM-system like Ruby's ActiveRecord, or DataMapper. Go ahead and open up app/models/todo.js. 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. So, minus the commented out code, you should have a file that looks like this:
var Todo = function () { this.defineProperties({ title: {type: 'string'} , status: {type: 'string'} }); }; Todo = geddy.model.register('Todo', Todo);

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`. To learn more, check out the readme.

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:
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);

For the title property, we made sure that the property is always present and we made sure that the title property is a minimum of 5 characters long. For the status property, we used a function to validate that the property is always set to either open or done. For more information about Geddy's Models, you can check out the Model wiki page. Model-adapter Now that we've set up our todo 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 memory model adapter. You can change the default memoryAdapter in config/development.js.
defaultAdapter: 'memory'

Now we've got a place to store our todo's. This is in your application's memory, so it will disappear when you restart the server. Optional: use mongo for persistence Install a mongodb server if you haven't already and $ [sudo] npm install mongodbwrapper to install the required mongodb-wrapper and set defaultAdapter = 'mongo' in config/development.js instead of the memory adapter. You will also have to specify the db configuration db: { mongo: { dbname: 'model_test' }. For more information see the Model API reference

Controller
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. Saving todos To save a todo we need to edit the create action in app/controllers/todos.js. It's not

doing much at the momment so lets modify it a little bit.


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}); } });

};

First, we create a new instance of the Todo model with geddy.model.Todo.create, passing in the title that our form will post up to us, and setting up the default status. Then we call we call the save method. Internally, save does two things. It validates the model based on the rules we defined earlier. This is similar to calling todo.isValid(). 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 self.redirect({controller: self.name});. Listing all todos Now that we we can create To Do items, we should probably list them somewhere. Lets change the index action in the todos controller. Open up /app/controllers/todos.js again and replace the current implementaton with the following code.
this.index = function (req, resp, params) { var self = this; geddy.model.Todo.all(function(err, todos) { self.respond({params: params, todos: todos}); });

};

This part is a bit simpler and it follows a similar pattern. Instead of calling create in geddy.model.Todo this time we simply call all and we pass the data back to the view for rendering Now that we can can load todo items you can test it by starting up Geddy and going to localhost:4000/todos and you can view the list of items. Showing a todo Now that we have our index action working as expected, we should work on the show controller action to display todo details.
this.show = function (req, resp, params) { var self = this; geddy.model.Todo.load(params.id, function(err, todo) { self.respond({params: params, todo: todo}); });

};

Now we have a working show action in the controller to load items. Updating a todo Alright, now that we can view our todos let's edit the update and edit actions in the todos controller. They should look something like this:
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}); } }); });

};

Deleting a todo 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 final version.

API
Check these urls out in your browser: GET: localhost:4000/todos.json GET: localhost:4000/todos/:id.json POST: localhost:4000/todos PUT: localhost:4000/todos/:id

Conclusion
At this point you should have a working To Do List app! If you want to explore a little more, here are some other things you could do: Change the Main#index route to point to the Todos#index action (hint, check out config/router.js) Add some logging with geddy.log

Configure mongo, riak or postgress and use it instead of the memory modelAdapter. See how easy it's to switch

copyright 2112 home documentation tutorial changelog community faq

geddy
homedocumentationtutorialchangelogcommunityfaq

Geddy Guide
Architecture CLI Templates Models I18n Authentication Deployment

Architecture
Geddy is built on the same MVC principles that many popular frameworks are based on. Every Geddy app has its models, controllers, and views as well as config files and routes.

structure
app controllers application.js main.js helpers models views layouts application.html.ejs main index.html.ejs config development.js environment.js init.js production.js router.js lib log node_modules public

config geddy.config Geddy has built in configuration management. Global config options should go in your 'config/environments.js` file. Likewise, your production and development config options should go in their respective files

If you want to start up your app in a specific environment, use the -e option:
$ geddy -e production

logger geddy.log[level] Geddy automatically logs requests to an access log, and you can log anything you'd like to stdout or a file. It supports 9 different log levels from debug to emergency.
levels

access: outputs to the access log and stdout debug: debug level logging info: info level logging notice: notice level logging warning: warning level logging error: error level logging, prints to stdout and stderr critical: critical level logging alert: alert level logging emergency: emergency level logging

examples geddy.log.debug('someting to debug') // prints `something to debug` to the console geddy.log.error('something went wrong') // prints 'something went wrong' to stderr and the console

CLI
Geddy has a robust CLI tool to help you generate apps, run tests or scripting tasks in your app, or interact with your app in a console. geddy Running the geddy command with no arguments will run the geddy app in the current directory.
$ cd path/to/app $ geddy // will run the app in path/to/app

Options: --environment, -e: Environment to use --hostname, -b: Host name or IP to bind the server to (default: localhost) --port, -p: Port to bind the server to (default: 4000) --geddy-root, -g: /path/to/approot The path to the root for the app you want to run (default is current working directory)

--workers, -w: Number of worker processes to start (default: 1) --debug, -d: Sets the log level to output debug messages to the console --help, -h: Output this usage dialog --version, -v: Output the version of Geddy that's installed

Examples
# Start Geddy on localhost:4000 in development mode or if the # directory isn't a Geddy app it'll display a prompt to use "geddy -h" geddy # Start Geddy on port 3000 geddy -p 3000 # Start Geddy in production mode geddy -e production # Generate a users scaffolding using Jade templates geddy -j scaffold user

geddy console This command starts a REPL in the context of your application. It will load your application's environment, and you can interact with all its models. Examples
# Start a REPL (in 'production' mode) geddy console # Start a REPL in 'development' mode geddy console environment=development

geddy gen [command] [options] [arguments] This is the generator script which you can use to create apps, resource scaffolds, or bare models and controllers. Commands gen app <name>: Create a new Geddy application gen resource <name> [attrs]: Create a new resource. A resource includes a model, controller and route gen scaffold <name> [attrs]: Create a new scaffolding. Scaffolding includes the views, a model, controller and route gen secret: Generate a new application secret in config/secret.json gen controller <name>: Generate a new controller including an index view and and a route gen model <name> [attrs]: Generate a new model gen auth[:update]: Creates user authentication for you, using Passport. gen migration <name>: Generate an empty migration for SQL databases For all of these commands, [attrs] is a list of attributes for the model, in the format of 'name:datatype' (e.g., foo:int). Options --realtime, -rt: When generating or scaffolding, take realtime into account --jade, -j: When generating views this will create Jade templates (Default: EJS) --handle, -H: When generating views this will create Handlebars templates (Default: EJS)

--mustache, -m: When generating views this will create Mustache templates (Default: EJS) --swig, -s: When generating views this will create Swig templates (Default: EJS) Examples
# Generate an app in a directory named 'foo' geddy gen app foo # Generate a users resource with the model properties name as a string and admin as a boolean geddy gen resource user name admin:boolean # Generate a users scaffolding user name as the default value to display data with geddy gen scaffold user name:string:default

geddy jake [task] [options] [env vars] This command runs a Jake task in the context of the current app. This allows you to run your tests or any other command-line tasks in the context of your application, with full access to your models. Geddy also ships with a number of useful Jake tasks built in, e.g., the routes task, which displays all the routes in your app. Options See https://github.com/mde/jake for full documentation Examples
# Run your app's tests in the app environment geddy jake test # Initialize the development database for your app geddy jake db:init environment=development # Show all routes geddy jake routes # Show all routes for the user resource geddy jake routes[user] # Show the index route for the user resource geddy jake routes[user.index]

Templates
Geddy's view layer provides a versatile set of templating languages and helpers to get you started quickly. The view layer supports these four templating engines: EJS(.ejs) Jade(.jade) Mustache(.mu, .ms, .mustache) Handlebars(.hbs, .handlebars) Swig(.swig)

To use a certain template engine just give the view a corresponding extension listed above. When using the Geddy CLI to generate parts of your application you can use different template languages by giving an argument to the command, here are some examples:
$ geddy app --mustache my_app $ geddy scaffold -m user

$ geddy app --jade my_app $ geddy scaffold -j user $ geddy app --handle my_app $ geddy scaffold -H user $ geddy app --swig my_app $ geddy scaffold --swig user

Models
Model currently implements adapters for: Postgres Riak MongoDB Defining models Model uses a pretty simple syntax for defining a model. (It should look familiar to anyone who has used an ORM like ActiveRecord, DataMapper, Django's models, or SQLAlchemy.)
var User = function () { this.property('login', 'string', {required: true}); this.property('password', 'string', {required: true}); this.property('lastName', 'string'); this.property('firstName', 'string'); this.validatesPresent('login'); this.validatesFormat('login', /[a-z]+/, {message: 'Subdivisions!'}); this.validatesLength('login', {min: 3}); this.validatesConfirmed('password', 'confirmPassword'); this.validatesWithFunction('password', function (s) { // Something that returns true or false return s.length > 0; }); // Can define methods for instances like this this.someMethod = function () { // Do some stuff };

};

// Can also define them on the prototype User.prototype.someOtherMethod = function () { // Do some other stuff }; User = model.register('User', User);

Abbreviated syntax

Alternatively, you can use the defineProperties method to lay out your model's properties in one go:
var User = function () {

this.defineProperties({ login: {type: 'string', required: true} , password: {type: 'string', required: true} , lastName: {type: 'string'} , firstName: {type: 'string'} });

Datatypes

Model supports the following datatypes: string text number int boolean date datetime time object

Creating instances Creating an instance of one of these models is easy:


var params = { login: 'alex' , password: 'lerxst' , lastName: 'Lifeson' , firstName: 'Alex' }; var user = User.create(params);

Validations Validations provide a nice API for making sure your data items are in a good state. When an item is "valid," it means that its data meet all the criteria you've set for it. You can specify that certain fields have to be present, have to be certain length, or meet any other specific criteria you want to set. Here's a list of supported validation methods: validatesPresent -- ensures the property exists validatesAbsent -- ensures the property does not exist validatesLength -- ensures the minimum, maximum, or exact length validatesFormat -- validates using a passed-in regex validatesConfirmed -- validates a match against another named parameter validatesWithFunction -- uses an arbitrary function to validate

Common options

You can specify a custom error message for when a validation fails using the 'message' option:
var Zerb = function () { this.property('name', 'string'); this.validatesLength('name', {is: 3, message: 'Try again, gotta be 3!'}); };

You can decide when you want validations to run by passing the 'on' option.
var User = function () { this.property('name', 'string', {required: false}); this.property('password', 'string', {required: false}); this.validatesLength('name', {min: 3, on: ['create', 'update']}); this.validatesPresent('password', {on: 'create'}); this.validatesConfirmed('password', 'confirmPassword', {on: 'create'}); }; // Name validation will pass, but password will fail myUser = User.create({name: 'aaa'});

The default behavior is for validation on both 'create' and 'update': create - validates on .create update - validates on .updateProperties You can also define custom validation scenarios other than create and update. (There is a builtin custom 'reify' scenario which is uses when instantiating items out of your datastore. This happens on the first and all query methods.)
// Force validation with the `reify` scenario, ignore the too-short name property myUser = User.create({name: 'aa'}, {scenario: 'reify'}); // You can also specify a scenario with these methods: // Enforce 'create' validations on a fetch -- may result in invalid instances User.first(query, {scenario: 'create'}, cb); // Do some special validations you need for credit-card payment User.updateProperties(newAttrs, {scenario: 'creditCardPayment'});

Validation errors

Any validation errors show up inside an errors property on the instance, keyed by field name. Instances have an isValid method that returns a Boolean indicating whether the instance is valid.
// Leaving out the required password field var params = { login: 'alex' }; var user = User.create(params); // Prints 'false' console.log(user.isValid()); // Prints 'Field "password" is required' console.log(user.errors.password);

Saving items After creating the instance, call the save method on the instance. This method takes a callback in the familiar (err, data) format for Node.
if (user.isValid()) { user.save(function (err, data) { if (err) { throw err; } console.log('New item saved!'); });

Updating items Use the updateProperties method to update the values of the properties on an instance with the appropriate validations. Then call save on the instance.
user.updateProperties({ login: 'alerxst' }); if (user.isValid()) { user.save(function (err, data) { if (err) { throw err; } console.log('Item updated!'); }); }

Lifecycle events Both the base model 'constructors,' and model instances are EventEmitters. They emit events during the create/update/remove lifecycle of model instances. In all cases, the plain-named event is fired after the event in question, the 'before'-prefixed event, of course happens before. The 'constructor' for a model emits the following events: beforeCreate create beforeValidate validate beforeUpdateProperties updateProperties beforeSave (new instances, single and bulk) save (new instances, single and bulk) beforeUpdate (existing single instances, bulk updates) update (existing single instances, bulk updates) beforeRemove remove beforeUpdateProperties updateProperties beforeSave save beforeUpdate update

Model-item instances emit these events:

Associations Model has support for associations: including hasMany/belongsTo and hasOne/belongsTo. For example, if you had a User model with a single Profile, and potentially many Accounts:
var User = function () { this.property('login', 'string', {required: true});

this.property('password', 'string', {required: true}); this.property('confirmPassword', 'string', {required: true}); this.hasOne('Profile'); this.hasMany('Accounts'); };

A Book model that belongs to an Author would look like this:


var Book = function () { this.property('title', 'string'); this.property('description', 'text'); this.belongsTo('Author'); };

Add the hasOne relationship by calling 'set' plus the name of the owned model in singular (in this case setProfile). Retrieve the associated item by using 'get' plus the name of the owned model in singular (in this case getProfile). Here's an example:
var user = User.create({ login: 'asdf' , password: 'zerb' , confirmPassword: 'zerb' }); user.save(function (err, data) { var profile; if (err) { throw err; } profile = Profile.create({}); user.setProfile(profile); user.save(function (err, data) { if (err) { throw err; } user.getProfile(function (err, data) { if (err) { throw err; } console.log(profile.id ' is the same as ' + data.id); }); }); });

Set up the hasMany relationship by calling 'add' plus the name of the owned model in singular (in this case addAccount). Retrieve the associated items with a call to 'get' plus the name of the owned model in plural (in this case getAccounts). An example:
var user = User.create({ login: 'asdf' , password: 'zerb' , confirmPassword: 'zerb' }); user.save(function (err, data) { if (err) { throw err; } user.addAccount(Account.create({})); user.addAccount(Account.create({})); user.save(function (err, data) {

if (err) { throw err; } user.getAccounts(function (err, data) { if (err) { throw err; } console.log('This number should be 2: ' + data.length); }); }); });

A belongsTo relationship is created similarly to a hasOne: by calling 'set' plus the name of the owner model in singular (in this case setAuthor). Retrieve the associated item by using 'get' plus the name of the owner model in singular (in this case getAuthor). Here's an example:
var book = Book.create({ title: 'How to Eat an Entire Ham' , description: 'Such a poignant book. I cried.' }); book.save(function (err, data) { if (err) { throw err; } book.setAuthor(Author.create({ familyName: 'Neeble' , givenName: 'Leonard' })); book.save(function (err, data) { if (err) { throw err; } book.getAuthor(function (err, data) { if (err) { throw err; } console.log('This name should be "Neeble": ' + data.familyName); }); }); });

'Through' associations

'Through' associations allow a model to be associated with another through a third model. A good example would be a Team linked to Players through Memberships.
var Player = function () { this.property('familyName', 'string', {required: true}); this.property('givenName', 'string', {required: true}); this.property('jerseyNumber', 'string', {required: true}); this.hasMany('Memberships'); this.hasMany('Teams', {through: 'Memberships'});

};

var Team = function () { this.property('name', 'string', {required: true}); this.hasMany('Memberships'); this.hasMany('Players', {through: 'Memberships'}); };

var Membership = function () { this.hasMany('Memberships'); this.hasMany('Teams'); };

The API for this is the same as with normal associations, using the set/add and get, with the appropriate association name (not the model name). For example, in the case of the Team adding Players, you'd use addPlayer and getPlayer.
Named associations

Sometimes you need mutliple associations to the same type of model (e.g., I have lots of Friends and Relatives who are all Users). You can accomplish this in Model using named associations:
var User = function () { this.property('familyName', 'string', {required: true}); this.property('givenName', 'string', {required: true}); }; this.hasMany('Kids', {model: 'Users'});

The API for this is the same as with normal associations, using the set/add and get, with the appropriate association name (not the model name). For example, in the case of Kids, you'd use addKid and getKids. Querying Model uses a simple API for finding and sorting items. Again, it should look familiar to anyone who has used a similar ORM for looking up records. The only wrinkle with Model is that the API is (as you might expect for a NodeJS library) asynchronous. Methods for querying are static methods on each model constructor.
Finding a single item

Use the first method to find a single item. You can pass it an id, or a set of query parameters in the form of an object-literal. In the case of a query, it will return the first item that matches, according to whatever sort you've specified.
var user; User.first({login: 'alerxst'}, function (err, data) { if (err) { throw err; } user = data; console.log('Found user'); console.dir(user); });

Collections of items

Use the all method to find lots of items. Pass it a set of query parameters in the form of an objectliteral, where each key is a field to compare, and the value is either a simple value for comparison (equal to), or another object-literal where the key is the comparison-operator, and the value is the value to use for the comparison.
var users , dt;

dt = new Date(); dt.setHours(dt.getHours() - 24); // Find all the users created since yesterday User.all({createdAt: {gt: dt}, function (err, data) { if (err) { throw err; } users = data; console.log('Found users'); console.dir(users); });

Here are some more examples of queries:


// Where "foo" is 'BAR' and "bar" is not null {foo: 'BAR', bar: {ne: null}} // Where "foo" begins with 'B' {foo: {'like': 'B'}} // Where foo is less than 2112, and bar is 'BAZ' {foo: {lt: 2112}, bar: 'BAZ'}

Comparison operators

Here is the list of comparison operators currently supported: eql: equal to ne: not equal to gt: greater than lt: less than gte: greater than or equal lte: less than or equal like: like

A simple string-value for a query parameter is the same as 'eql'. {foo: 'bar'} is the same as {foo: {eql: 'bar'}}. For case-insensitive comparisons, use the 'nocase' option. Set it to true to affect all 'like' or equality comparisons, or use an array of specific keys you want to affect.
// Zoobies whose "foo" begin with 'b', with no case-sensitivity Zooby.all({foo: {'like': 'b'}}, {nocase: true}, ... // Zoobies whose "foo" begin with 'b' and "bar" is 'baz' // The "bar" comparison will be case-sensitive, and the "foo" will not Zooby.all({or: [{foo: {'like': 'b'}}, {bar: 'baz'}]}, {nocase: ['foo']},

More complex queries Model supports combining queries with OR and negating queries with NOT. To perform an 'or' query, use an object-literal with a key of 'or', and an array of query-objects to represent each set of alternative conditions:
// Where "foo" is 'BAR' OR "bar" is 'BAZ' {or: [{foo: 'BAR'}, {bar: 'BAZ'}]} // Where "foo" is not 'BAR' OR "bar" is null OR "baz" is less than 2112 {or: [{foo {ne: 'BAR'}}, {bar: null}, {baz: {lt: 2112}}]}

To negate a query with 'not', simply use a query-object where 'not' is the key, and the value is the set of conditions to negate:
// Where NOT ("foo" is 'BAR' and "bar" is 'BAZ') {not: {foo: 'BAR', bar: 'BAZ'}} // Where NOT ("foo" is 'BAZ' and "bar" is less than 1001) {not: {foo: 'BAZ', bar: {lt: 1001}}}

These OR and NOT queries can be nested and combined:


// Where ("foo" is like 'b' OR "foo" is 'foo') and NOT "foo" is 'baz' {or: [{foo: {'like': 'b'}}, {foo: 'foo'}], not: {foo: 'baz'}}

Options: sort, skip, limit The all API-call for querying accepts an optional options-object after the query-conditions for doing sorting, skipping to particular records (i.e., SQL OFFSET), and limiting the number of results returned.
Sorting

Set a 'sort' in that options-object to specifiy properties to sort on, and the sort-direction for each one:
var users // Find all the users who have ever been updated, and sort by // creation-date, ascending, then last name, descending User.all({updatedAt: {ne: null}}, {sort: {createdAt: 'asc', lastName: 'desc'}}, function (err, data) { if (err) { throw err; } users = data; console.log('Updated users'); console.dir(users); });

Simplified syntax for sorting

You can use a simplified syntax for specifying the sort. The default sort-direction is ascending ('asc'), so you can specify a property to sort on (or multiple properties as an array) if you want all sorts to be ascending:
// Sort by createdAt, ascending {sort: 'createdAt'} // Sort by createdAt, then updatedAt, then lastName, // then firstName -- all ascending {sort: ['createdAt', 'updatedAt', 'lastName', 'firstName']}

Skip and limit

The 'skip' option allows you to return records beginning at a certain item number. Using 'limit' will return you only the desired number of items in your response. Using these options together allow you to implement pagination. Remember that both these option assume you have your items sorted in the desired order. If you don't sort your items before using these options, you'll end up with a random subset instead of the items you want.
// Returns items 501-600

{skip: 500, limit: 100}

Eager loading of associations (SQL adpaters only) You can use the 'includes' option to specify second-order associations that should be eager-loaded in a particular query (avoiding the so-called N + 1 Query Problem). This will also work for 'through' associations. For example, with a Team that hasMany Players through Memberships, you might want to display the roster of player for every team when you display teams in a list. You could do it like so:
var opts = { includes: ['players'] , sort: { name: 'desc' , 'players.familyName': 'desc' , 'players.givenName': 'desc' } }; Team.all({}, opts, function (err, data) { var teams; if (err) { throw err; } teams = data; teams.forEach(function (team) { console.log(team.name); team.players.forEach(function (player) { console.log(player.familyName + ', ' + player.givenName); }); }); });

Sorting results

Notice that it's possible to sort the eager-loaded associations in the above query. Just pass the association-names + properties in the 'sort' property. In the above example, the 'name' property of the sort refers to the team-names. The other two, 'players.familyName' and 'players.givenName', refer to the loaded associations. This will result in a list where the teams are initially sorted by name, and the contents of their 'players' list have the players sorted by given name, then first name.
Checking for loaded associations

The eagerly fetched association will be in a property on the top-level item with the same name as the association (e.g., Players will be in players). If you have an item, and you're not certain whether an association is already loaded, you can check for the existence of this property before doing a per-item fetch:
if (!someTeam.players) { someTeam.getPlayers(function (err, data) { console.dir(data); }); }

Migrations (SQL adapters only) Migrations are a convenient way to make changes to your SQL database schema over time, consistently and easily. They use a simply JavaScript API. This means that you don't have to write SQL by hand, and changes to your schema can be database independent. This is an example of a migration:
var CreateUsers = function () { this.up = function (next) { var def = function (t) { t.column('username', 'string'); t.column('password', 'string'); t.column('familyName', 'string'); t.column('givenName', 'string'); t.column('email', 'string'); } , callback = function (err, data) { if (err) { throw err; } else { next(); } }; this.createTable('users', def, callback); }; this.down = function (next) { var callback = function (err, data) { if (err) { throw err; } else { next(); } }; this.dropTable('users', callback); }; }; exports.CreateUsers = CreateUsers;

This migration will create a 'users' table a number of columns of string (varchar(256)) datatype. An 'id' column will be added implicitly, as well as timestamp columns for the 'createdAt' and 'updatedAt' properties of data items. (These will be in snake-case in the database, e.g., 'created_at'.) These properties are automatically managed by Model. The up method makes the change (in this case, creating the table), and the down method reverses the change. The down method is used to roll back undesirable changes.
Setting up your DB to use migrations

Inside your app, run geddy jake db:init to create the 'migrations' table. You have to do this before you can use migrations.
Creating a migration

Migrations live in the db/migrations folder in your application. The name is in the form YYYYMMDDHHMMSS_my_migration_name.js. Using these timestamps with migration names

allows you to run migrations in the order in which they're created, even with different developers working independently, creating migrations at overlapping times. To create a new migration, run the generator script:
$ ../geddy/bin/cli.js gen migration zerp_derp [Added] db/migrations/20130708212330_zerp_derp.js

If you open the new migration file, you'll see a blank migration file ready to be filled in:
var ZerpDerp = function () { this.up = function (next) { next(); }; this.down = function (next) { next(); }; }; exports.ZerpDerp = ZerpDerp;

Migrations API

createTable(name<string>, definition<function>, callback<function>) Creates a new table. The definition function is used to define the columns on the new table.
// CREATE TABLE distributors (id string PRIMARY KEY, address varchar(256), // created_at timestamp, updated_at timestamp); this.createTable('distributors', function (t) { t.column('address', 'string'); }, function (err, data) {});

dropTable(name<string>, callback<function>) Drops an existing table.


// DROP TABLE IF EXISTS distributors; this.dropTable('distributors', function (err, data) {});

addColumn(table<string>, column<string>, datatype<string>, callback<function>) Adds a column to an existing table.


// ALTER TABLE distributors ADD COLUMN address varchar(30); this.addColumn('distributors', 'address', 'string', function (err, data) {});

removeColumn(table<string>, column<string>, callback<function>) Removes a column from an existing table.


// ALTER TABLE distributors DROP COLUMN address; this.removeColumn('distributors', 'address', function (err, data) {});

changeColumn(table<string>, column<string>, datatype<string>, callback<function>) Changes a column on an existing table from one datatype to another.

// ALTER TABLE distributors ALTER COLUMN address TYPE text; this.changeColumn('distributors', 'address', 'text', function (err, data) {});

renameColumn(table<string>, column<string>, newColumn<string>, callback<function>) Renames a column on an existing table.


// ALTER TABLE distributors RENAME COLUMN address TO city; this.renameColumn('distributors', 'address', 'city', function (err, data) {});

Migrations for scaffolds

Using Geddy's scaffold-generators will also create the appropriate migration file for you. For example, with the following generator command:
$ geddy gen scaffold frang asdf:string qwer:int

You'll end up with the following migration to run to create the corresponding table for your model:
var CreateFrangs = function () { this.up = function (next) { var def = function (t) { t.column('asdf', 'string'); t.column('qwer', 'int'); } , callback = function (err, data) { if (err) { throw err; } else { next(); } }; this.createTable('frang', def, callback); }; this.down = function (next) { var callback = function (err, data) { if (err) { throw err; } else { next(); } }; this.dropTable('frang', callback); }; }; exports.CreateFrangs = CreateFrangs;

Migrations FAQ

Q: If I'm using Geddy-Passport for auth, how do I create the migrations for it? A: People running the auth generator will now get the migrations installed as well, but if you've previously installed the auth code, you can grab the migrations from here:

https://github.com/mde/geddy-passport/tree/master/db/migrations. They will create 'users' and 'passport' tables with the correct associations columns. Q: How do I handle associations with my migrations? A: Right now there is not great support for migrations in the CLI generators. You'll have to add the appropriate database-column entries into your migrations manually before you run them. Essentially, four steps: 1. Run the CLI scaffold generator to create your model-definition file, and your migration file. 2. Add the association (e.g., this.hasMany) into your model-definition file. 3. Add the appropriate database-column entry into your migration file. 4. Run the migration to create your database table. Here's an example from geddy-passport, with a hasMany and a belongsTo. We'll start with a User model:
var User = function () { this.defineProperties({ username: {type: 'string', required: true}, password: {type: 'string', required: true}, familyName: {type: 'string', required: true}, givenName: {type: 'string', required: true}, email: {type: 'string', required: true} }); this.validatesLength('username', {min: 3}); this.validatesLength('password', {min: 8}); this.validatesConfirmed('password', 'confirmPassword'); this.hasMany('Passports'); }; exports.User = User;

A User model has many Passports, and a Passport belongs to a User:


var Passport = function () { this.defineProperties({ authType: {type: 'string'}, key: {type: 'string'} }); }; this.belongsTo('User');

exports.Passport = Passport;

This association will need a 'userId' property (a 'user_id' column) on the Passport. Here's the migration:
var CreatePassports = function () { this.up = function (next) { var def = function (t) { var datatype = geddy.model.autoIncrementId ? 'int' : 'string'; t.column('authType', 'string'); t.column('key', 'string'); t.column('userId', datatype); // belongsTo User } , callback = function (err, data) { if (err) { throw err; } else {

next(); } }; this.createTable('passports', def, callback); }; this.down = function (next) { var callback = function (err, data) { if (err) { throw err; } else { next(); } }; this.dropTable('passports', callback); }; }; exports.CreatePassports = CreatePassports;

If you know what type of ids you're using, then you can skip the check for the 'userId' datatype -just make it the same as the 'id' column on the owner object. Q: What happens if I change the associations, do I then re-run the migrations? A: Right now, you'll have to manage the association columns manually with addColumn and removeColumn. Better support for assocations in the CLI and in migrations is coming in the next version of Geddy. Q: How can I take an older Geddy app that has all its models and turn them into a migrations-based thing? A: The easiest thing to do would be to create a separate Geddy app, and use the generator scripts to create the migrations you want. Run those migrations in an empty DB, then import your data into that database using whatever tools your DB provides (e.g., pg_dump).

I18n
Geddy provides internationalization support out of the box, with localized error messages in the following languages: Chinese (Simplified) English (US) German (Germany) Japanese (Japan) Portuguese (Brazil) Spanish (Spain)

You can set a specific locale at the request level, or a default one for your entire app. The default locale if you don't set one is American English ('en-us'). Setting a locale for your app Set a locale in your environment.js by setting the defaultLocale property on the i18n config option:
... , i18n: { defaultLocale: 'ja-jp'

} ...

Setting locale at the controller-level You can set the desired locale at the controller level, rather than for the entire app. Inside your controller action:
this.i18n.setLocale('zh-cn');

Loading i18n data

Geddy will load i18n data according to the loadPaths property of your app's i18n config -- an array of paths to look in for JSON files containing i18n data. By default, it contains an entry for 'config/locales' in your app. Geddy's i18n code loads the data into data structures based on the filename. (So the data in /foo/bar/en-uk.json gets loaded into the en-uk locale, etc.)
Data format

Internationalization data is loaded from JSON files in the following format:


{ , , , , , , , } "model.validatesPresent": "{name}" "model.validatesAbsent": "{name}" "model.validatesConfirmed": "{name}{qual}" "model.validatesFormat": "{name}" "model.validatesExactLength": "{name}{qual}" "model.validatesMinLength": "{name}{min}" "model.validatesMaxLength": "{name}{max}" "model.validatesWithFunction": "{name}"

Using i18n text Geddy controllers have an i18n property which has a getText method (shortcut alias t). Pass this method the desired key, and an optional data-object for parametric replacement, and an optional locale. If you don't pass a locale, it will fall back to the app's defaultLocale. This i18n object is also available as a local variable in your templates. Use it like this in a controller (assuming a defaultLocale of 'ja-jp'):
// Returns HOWDY this.i18n.t('model.validatesPresent', {name: 'HOWDY'}); // Returns "HOWDY" ist ein Pflichtfeld. this.i18n.t('model.validatesPresent', {name: 'HOWDY'}, 'de-de');

Authentication
Geddy provides built-in authentication which integrates with Passport to allow auth against either local accounts or third-party social services like Facebook and Twitter.

Using the generator To set up a new Geddy app with built-in authentication, create your application like normal, then run the geddy auth command inside, like so:
$ geddy app by_tor $ cd by_tor $ geddy auth

This will pull down Geddy-Passport using NPM, and install all the needed code into your app. This includes the needed Passport libraries, and the Geddy models and controllers for the local User accounts and the login process. Danger, Warning, etc. The geddy auth generator should only be used in a new Geddy app. If you run it inside an existing app, it may overwrite existing files that you wanted to keep. If you need to add auth to an existing app, you can take a look at the Geddy-Passport project, which is itself a Geddy app scaffold, and use the pieces you need. Configuring Passport You'll need to add the settings for Passport in your config/secrets.json file. That includes the redirect locations for after an auth failure/success, and the OAuth keys for your app. The setting will look similar to this:
{ "passport": { "successRedirect": "/", "failureRedirect": "/login", "twitter": { "consumerKey": "XXXXXX", "consumerSecret": "XXXXXX" }, "facebook": { "clientID": "XXXXXX", "clientSecret": "XXXXXX" }, "yammer": { "clientID": "XXXXXX", "clientSecret": "XXXXXX" } } }

Local users Local User accounts just go through the usual RESTful actions you'd get in a normal Geddy resource. Start at "/users/add" to create a new User. You can modify "/app/models/user.js" to add any other properties you want. Login with third-party services A successful login with a third-party service like Facebook or Twitter will create a linked local User account if one does not exist.

Authenticated users After a user successfully authenticates, she will end up redirected to the successRedirect you've specified, and there will be two new items in the user's session: userId -- the id for the local User account authType -- the method of authentication (e.g., 'local', 'twitter') Requiring authentication in your app Use a before-filter, and redirect to the login page if there is no userId in the user's session. If there is a userId, that means the user is authenticated. There is a built-in reequireAuth function in the Passport helper-library, which does just this. The User controller for local accounts is protected like this:
var passport = require('../helpers/passport') , cryptPass = passport.cryptPass , requireAuth = passport.requireAuth; var Users = function () { this.before(requireAuth, { except: ['add', 'create'] }); // Rest of controller omitted

This allows new accounts to be created, because the 'add' and 'create' actions are exempted, but only authenticated users can view or update existing users.

Deployment
We use the following example as a reference. There will be some differences with other environments. Windows Azure
Pre-requisites

1. Install the azure-cli module.


npm install -g azure-cli

2. Download your Azure .publishsettings file. You will be asked to login with your Azure credentials. If you do not have an account you can create one for free.
azure account download

3. Import your .publishsettings file


azure account import [file]

4. Install Geddy. If you're new, you can start with the tutorial
Notes

Your Geddy app is deployed via Git, which will ignore anyhting specified in the .gitignore including the config/secrets.json file.

If you need something that requires the secret such as sessions, etc. you'll encounter errors about doing geddy secret when you deploy. Currently there's no way to circumvent this other than removing it from your .gitignore file. More info here: https://github.com/mde/geddy/issues/309 Now we need to create a server.js file which Windows Azure will pick up for running Geddy server:
var geddy = require('geddy'); geddy.start({ port: process.env.PORT || '3000', // you can manually set the environment, or configure to use the node_env setting which is configurable via iisnode.yml after the site is created. environment: 'production' // To configure based on NODE_ENV use the following: //environment: process.env.NODE_ENV || 'development' });

In the object we're giving to geddy.start you can use any other arguments you'd for the configuration files, these will override the ones loaded for the environment. For more information about this file you can go here Open you .gitignore file and remove the line for config\secrets.json - note: This is insecure, on public repo's as it exposes your cookie's secret hash. Now it's time to create a node site. Subsitute 'mysite' below with your site name.
azure site create mysite --git

After selecting a location add everything to git and push to Windows Azure
git push azure master

For more information about deploying and supporting Node Apps on Windows Azure Websites see the Command Line Tools How-To-Guide article. To learn more about Node Websites in Windows Azure see this article/) Nodejitsu
Pre-requisites

1. 2. 3. 4.
Notes

Install the jitsu module Install Geddy. If you're new, you can start with the tutorial Create a Nodejitsu account(Not required: we'll go over creating one from the CLI) Have an app ready to be deployed

Nodejitsu reads the deployed .gitignore file, so if you have the config/secrets.json file in there(you should), then you'll encounter errors about needing to do geddy secret if you need the secrets for sessions, etc. To circumvent this, create a .npmignore file and include all the contents from the .gitignore except the config/secrets.json line. Nodejitsu ignores the .gitignore file only if a .npmignore file is included as well. If you haven't already you'll need to sign up and log in to Nodejitsu which you can do from the jitsu executable.
jitsu signup jitsu login

Now once you've created an account on Nodejitsu we need to prepare the application you have for deployment. First we'll edit(or create) a package.json file in the app's root directory
{ "name": "node-example", "version": "0.0.1", "dependencies": { "geddy": "0.6.x" }, "subdomain": "geddy-example", "scripts": { "start": "app.js" }, "engines": { "node": "0.8.x" }

Here we have a subdomain key/value this tells Nodejitsu what subdomain to host the application on(e,g,. geddy-example.jit.su). We also have a start script pointing to app.js in the root directory, we'll go over what to put here in a second. Of course you should edit this to include anything else you want, like other dependences or an author. Now we need to create a app.js file so that Nodejitsu can use it to boot the Geddy server, here's what it should look like
var geddy = require('geddy'); geddy.start({ environment: 'production' });

In the object we're giving to geddy.start you can use any other arguments you'd for the configuration files, these will override the ones loaded for the environment. For more information about this file you can go here Now that our application is set up for deployment, we need to deploy it which is just a single command
jitsu deploy

Now you can go to http://geddy-example.jit.su and see your application! Heroku


Pre-requisites

1. 2. 3. 4.
{

Install heroku toolbelt Install Geddy. If you're new, you can start with the tutorial Be familiar with GIT, the basic geddy commands, and heroku's deployment models Have an app ready to be deployed.

Add a package.json file to your app's root directory


"name": "node-example", "version": "0.0.1", "dependencies": { "geddy": "0.9.x" },

"engines": { "node": "0.10.x", "npm": "1.2.x" }

Add a .env text file to your app's root directory. This is read by Foreman run booting the app locally.
NODE_ENV=development

Add a Procfile text file to your app's root directory. This is read by Heroku when booting the app.
web: geddy --environment $NODE_ENV

Now it's time to create a heroku app.


$ heroku create --stack cedar

Add the NODE_ENV environment variable to Heroku.


heroku config:set NODE_ENV=production

Add everything to git and push to Heroku.


$ git push heroku master

Database Add-Ons

Heroku gives you a database connection url, which you will need to parse. First, add the database of your choice:
heroku addons:add mongohq:sandbox

This will give you a new environment variable that looks like this:
MONGOHQ_URL: mongodb://<user>:<pass>@hatch.mongohq.com:10034/app003132345

You have to use something like parse_url to parse the URL into individual options. Edit your config/production.js to parse the URL:
// See `parse_url` above var MONGO_PARSED = parse_url(process.env.MONGOHQ_URL); var config = { detailedErrors: false , debug: false , hostname: "0.0.0.0" , port: process.env.PORT || 4000 , model: { defaultAdapter: 'mongo' } , db: { mongo: { username: MONGO_PARSED.user , dbname: MONGO_PARSED.path.substring(1) , password: MONGO_PARSED.pass , host: MONGO_PARSED.host , port: parseInt(MONGO_PARSED.port)

// Get rid of the leading `/`

} } , sessions: { store: 'cookie' , key: 'did' , expiry: 14 * 24 * 60 * 60 } }; module.exports = config;

Your app should now be configured for the database add-on.


Secrets

If your app uses sessions or auth, you'll need to push your secrets.json file to Heroku. To do this securely, you'll have to use environment variables. First, open up secrets.json and add each secret into your .env file. For example, if your config/secrets.json file looks like this:
{ "passport": { "loginPath": "/login", "successRedirect": "/", "failureRedirect": "/login?failed=true", "twitter": { "consumerKey": "secret1", "consumerSecret": "secret2" }, "facebook": { "clientID": "secret3", "clientSecret": "secret4" } }, "secret":"secret5"

Your .env file should look something like this:


NODE_ENV=development TWITTER_KEY=secret1 TWITTER_SECRET=secret2 FACEBOOK_ID=secret3 FACEBOOK_SECRET=secret4 GEDDY_SECRET=secret5

You'll have to run a command like the following to save the environment variables to Heroku:
heroku config:set TWITTER_KEY=secret1 TWITTER_SECRET=secret2 FACEBOOK_ID=secret3 FACEBOOK_SECRET=secret4 GEDDY_SECRET=secret5

Finally, replace the secrets in your secrets.json with EJS:


{ "passport": { "loginPath": "/login", "successRedirect": "/", "failureRedirect": "/login?failed=true", "twitter": { "consumerKey": "<%= process.env.TWITTER_KEY %>",

"consumerSecret": "<%= process.env.TWITTER_SECRET %>" }, "facebook": { "clientID": "<%= process.env.FACEBOOK_ID %>", "clientSecret": "<%= process.env.FACEBOOK_SECRET %>" } }, "secret":"<%= process.env.GEDDY_SECRET %>"

Now remove secrets.json from your .gitignore file and push it to Heroku. For more information about deploying and supporting Node Apps on Heroku see the Getting Started with Node.js on Heroku article.

copyright 2112 home documentation tutorial changelog community faq

You might also like