Demo for General Assembly WDI.
- Give brief explanation on CMS, WordPress, ActiveAdmin, etc. King & Partners example.
- Talk about Yeoman generator. Aren't going to use it.
- Touch a server.js file.
- Run NPM init.
- Install dependencies.
- keystone
- express-handlebars
server.js
file:
- additional setup explanation can be found: http://keystonejs.com/docs/configuration/
var keystone = require('keystone');
var handlebars = require('express-handlebars')
keystone.init({
'name': 'ga_keystone',
'favicon': 'public/favicon.ico',
'static': 'public',
'views': 'templates/views',
'view engine': 'hbs',
'custom engine': handlebars.create({
layoutsDir: 'templates/layouts',
defaultLayout: 'default',
extname: '.hbs'
}).engine,
'auto update': true,
'mongo': 'mongodb://localhost/ga_keystone',
'session': true,
'auth': true,
'user model': 'User',
'cookie secret': 'youcanthavethecrabstillyoufinishthelab'
});
require('./models');
keystone.set('routes', require('./routes'));
keystone.start();
- Set up project structure.
- models
- node_modules
- public
- routes
- views
- templates
- views
- layouts
- updates
package.json
server.js
- First model, a
user
. Create an index.js inside yourmodels
folder. This is where we'll be requiring all our models.
models/index.js
require('./User.js');
models/User.js
var keystone = require('keystone');
Types = keystone.Field.Types;
// reference documentation to discuss Field Types
var User = new keystone.List('User');
// var User = mongoose.model("User", userSchema);
User.add({
name: { type: Types.Name, required: true },
email: { type: Types.Email, initial: true, required: true},
password: { type: Types.Password, initial: true, required: true },
canAccessKeystone: { type: Boolean, initial: true }
});
User.register();
- Setting up routes / controllers. Create an index.js inside your routes folder. Reference documentation to explain route binding.
routes/index.js
var keystone = require('keystone');
importRoutes = keystone.importer(__dirname);
// Load Routes
var routes = {
views: importRoutes('./views')
};
// Bind Routes
exports = module.exports = function(app) {
app.get('/', routes.views.index);
};
- Lets create a controller for our main view.
routes/views/index.js
var keystone = require('keystone');
const async = require('async');
exports = module.exports = function(req, res){
var view = new keystone.View(req , res);
view.render('index');
};
- Lets create our first layout, inside
templates/views/layouts
calleddefault.hbs
. This references the "default" we set in our server.js.
templates/layouts/default.hbs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<title>KEYSTONE</title>
</head>
<body>
<div class="container">
{{{body}}}
<a href="/keystone">Admin</a>
</div>
</body>
</html>
- Next we'll set up an actual view for the main index of our site. In
templates/views
calledindex.hbs
.
templates/views/index.hbs
<h1> Hello, there. I sure hope this works </h1>
- Create a file called
0.0.1-admin.js
inside your updates folder.
updates/0.0.1-admin.js
var keystone = require('keystone'),
User = keystone.list('User');
exports = module.exports = function(done) {
new User.model({
name: { first: 'Greg', last: 'Dunn' },
email: '[email protected]',
password: 'password',
canAccessKeystone: true
}).save(done);
};
- Log into keystone as [email protected]. Show admin ui. Create a new user, change password. Filter search results. Delete new user. Pull up Mongo client, show password encryption automatically.
- Create
Post.js
inside models folder.
models/Post.js
var keystone = require('keystone');
Types = keystone.Field.Types;
var Post = new keystone.List('Post', {
autokey: { path: 'slug', from: 'title', unique: true },
map: { name: 'title' },
defaultSort: '-createdAt'
});
Post.add({
title: { type: String, required: true },
state: { type: Types.Select, options: 'draft, published, archived', default: 'draft' },
author: { type: Types.Relationship, ref: 'User' },
createdAt: { type: Date, default: Date.now },
publishedAt: Date,
content: { type: Types.Html, wysiwyg: true, height: 400 },
});
Post.register();
- Don't forget to require the new
Post.js
model inside the models/index.js.
models/index.js
require('./User.js');
require('./Post.js');
- Log back into application as [email protected], show Admin UI with
Post
model creatable. Create a few new posts, with different states.
- We'll need to tell the controller in charge of '/' (index.js) to fetch data from the DB and serve it up to the view. We're gonna use res.locals to do this.
routes/views/index.js
// inside the module.exports
var locals = res.locals;
view.on('init', function(next) {
var post = Post.model.find().where('state', 'published').sort('-publishedDate').populate('author')
post.exec(function(err, results) {
console.log(results);
locals.posts = results;
next(err);
});
});
- Don't forget to require the
Post
model at the top header with the other requires.
const Post = keystone.list('Post')
- Test hitting route, and checking node for results. (posts).
- Inside our templates/views/index.hbs file, lets write some code to display all our posts.
templates/views/index.hbs
<h1> Hello, there. I sure hope this works </h1>
<hr>
<h4> Posts </h4>
/*<% posts.forEach(function (post, i) { %>*/
{{#each posts}}
<p>
{{this.title}} | by {{this.author.name.first}} {{this.author.name.last}} </br>
{{{this.content}}
<hr>
</p>
{{/each}}
- Go back into the Admin UI and create a third post without published. Then switch to published.
- Create a new
PostCategory.js
model inside models directory.
models/PostCategory.js
var keystone = require('keystone');
Types = keystone.Field.Types;
var PostCategory = new keystone.List('PostCategory', {
autokey: { from: 'name', path: 'key', unique: true }
});
PostCategory.add({
name: { type: String, required: true }
});
PostCategory.relationship({ ref: 'Post', path: 'categories' });
PostCategory.register();
- We have to update our
Post.js
model to reflect this relationship.
models/Post.js
// add this to our schema
categories: { type: Types.Relationship, ref: 'PostCategory', many: true }
- Don't forget to include this new
PostCategory.js
model inside our mainindex.js
model file.
models/index.js
require('./User.js');
require('./Post.js');
require('./PostCategory');
- Update the posts to include categories. Check the Mongo CLI and show the categories displayed just as object IDs.
- In our templates/index.hbs file, add the following code under
this.content
.
templates/views/index.hbs
{{#each this.categories}}
<mark>{{this.name}}</mark>
{{/each}}
- Don't forget to head to routes/views/index.js to incldue the
.populate()
method oncategories
.
routes/views/index.js
.populate('categories');
- Refresh page to display the categories.