├── README ├── app.js ├── postprovider.js ├── public └── stylesheets │ ├── style.css │ └── style.sass ├── test └── app.test.js └── views ├── comment.ejs ├── index.ejs ├── layout.ejs ├── post.ejs ├── post_edit.ejs ├── post_new.ejs └── post_show.ejs /README: -------------------------------------------------------------------------------- 1 | A simple example of a blog using Node.js, MongoDB, Mongoose, Sass and Express. It is based off of the excellent tutorial at http://howtonode.org/express-mongodb. The code has been modified to use npm (instead of kiwi), Mongoose and EJS, and runs on newer versions of node. 2 | 3 | To run this, install node.js and mongodb then run the following (may require sudo access): 4 | npm install express 5 | npm install express-messages 6 | npm install ejs 7 | npm install sass 8 | npm install mongoose 9 | 10 | Then cd into the directory and run: 11 | node app.js 12 | 13 | You should be able to access the blog at: 14 | http://localhost:3000 15 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var express = require('express'); 7 | 8 | var app = module.exports = express.createServer(); 9 | 10 | // Configuration 11 | var pub = __dirname + '/public'; 12 | 13 | app.configure(function(){ 14 | app.set('views', __dirname + '/views'); 15 | app.set('view engine', 'ejs'); 16 | app.use(express.bodyParser()); 17 | app.use(express.methodOverride()); 18 | app.use(express.compiler({ src: pub, enable: ['sass'] })); 19 | app.use(express.static(pub)); 20 | app.use(app.router); 21 | }); 22 | 23 | app.configure('development', function(){ 24 | app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); 25 | }); 26 | 27 | app.configure('production', function(){ 28 | app.use(express.errorHandler()); 29 | }); 30 | 31 | var PostProvider = require('./postprovider').PostProvider; 32 | var PostProvider= new PostProvider(); 33 | 34 | //Blog index 35 | app.get('/', function(req, res){ 36 | PostProvider.findAll(function(error, posts){ 37 | res.render('index', { 38 | locals: { 39 | title: 'Mongo Node.js Blog', 40 | posts: posts 41 | } 42 | }); 43 | }) 44 | }); 45 | 46 | //new 47 | app.get('/posts/new', function(req, res){ 48 | res.render('post_new', { 49 | locals: { 50 | title: 'New Post' 51 | } 52 | }); 53 | }); 54 | 55 | //create 56 | app.post('/posts/new', function(req, res){ 57 | PostProvider.save({ 58 | title: req.param('title'), 59 | body: req.param('body') 60 | }, function(error, docs) { 61 | res.redirect('/'); 62 | }); 63 | }); 64 | 65 | //show 66 | app.get('/posts/:id', function(req, res){ 67 | PostProvider.findById(req.param('id'), function(error, post) { 68 | res.render('post_show', { 69 | locals: { 70 | title: post.title, 71 | post:post 72 | } 73 | }); 74 | }); 75 | }); 76 | 77 | //edit 78 | app.get('/posts/:id/edit', function(req, res){ 79 | PostProvider.findById(req.param('id'), function(error, post) { 80 | res.render('post_edit', { 81 | locals: { 82 | title: post.title, 83 | post:post 84 | } 85 | }); 86 | }); 87 | }); 88 | 89 | //update 90 | app.post('/posts/:id/edit', function(req, res){ 91 | PostProvider.updateById(req.param('id'), req.body, function(error, post) { 92 | res.redirect('/'); 93 | }); 94 | }); 95 | 96 | //add comment 97 | app.post('/posts/addComment', function(req, res){ 98 | PostProvider.addCommentToPost(req.body._id, { 99 | person: req.body.person, 100 | comment: req.body.comment, 101 | created_at: new Date() 102 | }, function(error, docs) { 103 | res.redirect('/posts/' + req.body._id) 104 | }); 105 | }); 106 | 107 | // Only listen on $ node app.js 108 | 109 | if (!module.parent) { 110 | app.listen(3000); 111 | console.log("Express server listening on port %d", app.address().port); 112 | } 113 | -------------------------------------------------------------------------------- /postprovider.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | mongoose.connect('mongodb://localhost/my_blog'); 3 | 4 | var Schema = mongoose.Schema 5 | , ObjectId = Schema.ObjectId; 6 | 7 | var Comments = new Schema({ 8 | person : String 9 | , comment : String 10 | , created_at : Date 11 | }); 12 | 13 | var Post = new Schema({ 14 | author : ObjectId 15 | , title : String 16 | , body : String 17 | , created_at : Date 18 | , comments : [Comments] 19 | }); 20 | 21 | mongoose.model('Post', Post); 22 | var Post = mongoose.model('Post'); 23 | 24 | PostProvider = function(){}; 25 | 26 | //Find all posts 27 | PostProvider.prototype.findAll = function(callback) { 28 | Post.find({}, function (err, posts) { 29 | callback( null, posts ) 30 | }); 31 | }; 32 | 33 | //Find post by ID 34 | PostProvider.prototype.findById = function(id, callback) { 35 | Post.findById(id, function (err, post) { 36 | if (!err) { 37 | callback(null, post); 38 | } 39 | }); 40 | }; 41 | 42 | //Update post by ID 43 | PostProvider.prototype.updateById = function(id, body, callback) { 44 | Post.findById(id, function (err, post) { 45 | if (!err) { 46 | post.title = body.title; 47 | post.body = body.body; 48 | post.save(function (err) { 49 | callback(); 50 | }); 51 | } 52 | }); 53 | }; 54 | 55 | //Create a new post 56 | PostProvider.prototype.save = function(params, callback) { 57 | var post = new Post({title: params['title'], body: params['body'], created_at: new Date()}); 58 | post.save(function (err) { 59 | callback(); 60 | }); 61 | }; 62 | 63 | //Add comment to post 64 | PostProvider.prototype.addCommentToPost = function(postId, comment, callback) { 65 | this.findById(postId, function(error, post) { 66 | if(error){ 67 | callback(error) 68 | } 69 | else { 70 | post.comments.push(comment); 71 | post.save(function (err) { 72 | if(!err){ 73 | callback(); 74 | } 75 | }); 76 | } 77 | }); 78 | }; 79 | 80 | exports.PostProvider = PostProvider; 81 | -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Helvetica Neue", "Lucida Grande", "Arial"; 3 | font-size: 13px; 4 | text-align: center; 5 | -webkit-text-stroke: 1px rgba(255, 255, 255, 0.1); 6 | -moz-text-stroke: 1px rgba(255, 255, 255, 0.1); 7 | color: #555;} 8 | 9 | h1, h2 { 10 | margin: 0; 11 | font-size: 22px; 12 | color: #343434;} 13 | 14 | h1 { 15 | text-shadow: 1px 2px 2px #ddd; 16 | font-size: 60px;} 17 | 18 | #articles { 19 | text-align: left; 20 | margin-left: auto; 21 | margin-right: auto; 22 | width: 320px;} 23 | #articles .article { 24 | margin: 20px;} 25 | #articles .article .created_at { 26 | display: none;} 27 | #articles .article .title { 28 | font-weight: bold; 29 | text-decoration: underline; 30 | background-color: #eee;} 31 | #articles .article .body { 32 | background-color: #ffa;} 33 | 34 | #article .created_at { 35 | display: none;} 36 | #article input[type =text] { 37 | width: 490px; 38 | margin-left: 16px;} 39 | #article input[type =button] { 40 | text-align: left; 41 | margin-left: 440px;} 42 | #article textarea { 43 | width: 490px; 44 | height: 90px;} 45 | -------------------------------------------------------------------------------- /public/stylesheets/style.sass: -------------------------------------------------------------------------------- 1 | body 2 | :font-family "Helvetica Neue", "Lucida Grande", "Arial" 3 | :font-size 13px 4 | :text-align center 5 | =text-stroke 1px rgba(255, 255, 255, 0.1) 6 | :color #555 7 | h1, h2 8 | :margin 0 9 | :font-size 22px 10 | :color #343434 11 | h1 12 | :text-shadow 1px 2px 2px #ddd 13 | :font-size 60px 14 | #articles 15 | :text-align left 16 | :margin-left auto 17 | :margin-right auto 18 | :width 320px 19 | .article 20 | :margin 20px 21 | .created_at 22 | :display none 23 | .title 24 | :font-weight bold 25 | :text-decoration underline 26 | :background-color #eee 27 | .body 28 | :background-color #ffa 29 | #article 30 | .created_at 31 | :display none 32 | input[type =text] 33 | :width 490px 34 | :margin-left 16px 35 | input[type =button] 36 | :text-align left 37 | :margin-left 440px 38 | textarea 39 | :width 490px 40 | :height 90px -------------------------------------------------------------------------------- /test/app.test.js: -------------------------------------------------------------------------------- 1 | 2 | // Run $ expresso 3 | 4 | /** 5 | * Module dependencies. 6 | */ 7 | 8 | var app = require('../app') 9 | , assert = require('assert'); 10 | 11 | 12 | module.exports = { 13 | 'GET /': function(){ 14 | assert.response(app, 15 | { url: '/' }, 16 | { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' }}, 17 | function(res){ 18 | assert.includes(res.body, 'Express'); 19 | }); 20 | } 21 | }; -------------------------------------------------------------------------------- /views/comment.ejs: -------------------------------------------------------------------------------- 1 |
2 |
<%= comment.created_at %>
3 |
<%= comment.person %>
4 |
<%= comment.comment %>
5 |
-------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 |
2 | <%- partial('post', posts) %> 3 |
-------------------------------------------------------------------------------- /views/layout.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

<%= title %>

7 |

Home

8 |
9 | <%- body %> 10 |
11 | New 12 | 13 | -------------------------------------------------------------------------------- /views/post.ejs: -------------------------------------------------------------------------------- 1 |
2 |
<%= post.title %>
3 |
<%= post.created_at %>
4 |
<%= post.body %>
5 |
-------------------------------------------------------------------------------- /views/post_edit.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | Title : 5 | 6 |
7 |
8 | Body : 9 | 10 |
11 |
12 | 13 |
14 |
15 |
-------------------------------------------------------------------------------- /views/post_new.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | Title : 5 | 6 |
7 |
8 | Body : 9 | 10 |
11 |
12 | 13 |
14 |
15 |
-------------------------------------------------------------------------------- /views/post_show.ejs: -------------------------------------------------------------------------------- 1 |

2 |
3 |
<%= post.created_at %>
4 |
<%= post.title %>
5 |
<%= post.body %>
6 |
7 | <%- partial('comment', post.comments) %> 8 |
9 |
10 |
11 | 12 |
13 | Author : 14 | 15 |
16 |
17 | Comment : 18 | 19 |
20 |
21 | 22 |
23 |
24 |
25 | Edit 26 |
--------------------------------------------------------------------------------