gist

ラベル MongoDB の投稿を表示しています。 すべての投稿を表示
ラベル MongoDB の投稿を表示しています。 すべての投稿を表示

2012年4月10日火曜日

Node.js「脱」初心者!CoffeeBoxでブログの作り方を学ぼう!

CoffeeBoxは、Node.js、CoffeeScript、MondoDbで作成されたシンプルなブログアプリです。

そこそこ本格的で「学べる」コードだと思いますので、インストールから触りだけ読んでみたいと思います。

UIもキレイです。

インストールして起動まで一気に。

$ git clone https://github.com/qiao/coffee-box
$ cd coffee-box/
$ npm install
$ mongod --dbpath ~/MongoDb (MongoDBを起動しておきます)
$ node index.js
coffee-box server listening on port 3000 in development mode


http://localhost:3000 にアクセスします。

Login画面。OpenIDを使えます。

新規投稿です。

投稿完了。

ダッシュボード。

コードを少し見てみます。

ファイル構成です。

index.js
server.coffee
lib
├── markdown.coffee
├── marked.js
├── require_dir.coffee
└── taglist.coffee
public/
├── 404.html
├── favicon.ico
└── images
    ├── CREDIT
    └── fabric_1.png
scripts/
└── populate.coffee
config/
├── config.coffee
├── routes.coffee
└── site.json
app
├── assets
│   ├── javascripts
│   │   ├── application.coffee
│   │   ├── bootstrap-tabs.js
│   │   ├── comments.coffee
│   │   ├── jquery.elastic.js
│   │   ├── jquery.js
│   │   ├── jquery.textarea.js
│   │   ├── preview.coffee
│   │   ├── session.coffee
│   │   └── site.coffee
│   └── stylesheets
│       ├── application.styl
│       ├── bootstrap.css
│       ├── comments.styl
│       ├── dashboard.styl
│       ├── posts.styl
│       ├── pygments.css
│       ├── session.styl
│       └── site.styl
├── controllers
│   ├── comments_controller.coffee
│   ├── dashboard_controller.coffee
│   ├── posts_controller.coffee
│   └── session_controller.coffee
├── helpers
│   ├── comments_helper.coffee
│   └── posts_helper.coffee
├── models
│   ├── comment.coffee
│   └── post.coffee
└── views
    ├── comments
    │   ├── _comment.jade
    │   ├── _comments.jade
    │   ├── _form.jade
    │   └── _spam.jade
    ├── dashboard
    │   ├── _comments.jade
    │   ├── _posts.jade
    │   └── index.jade
    ├── layouts
    │   ├── _footer.jade
    │   ├── _header.jade
    │   └── layout.jade
    ├── posts
    │   ├── _form.jade
    │   ├── edit.jade
    │   ├── index.jade
    │   ├── new.jade
    │   └── show.jade
    └── session
        └── new.jade

MVCにわかれています。ViewテンプレートにはJadeを使っています。スタイルシートはStylus。

次に依存パッケージを見ていきます。

coffee-box@0.0.6 /Users/inouetomoyuki/Projects/node/coffee-box
├── async@0.1.18 
├── coffee-script@1.2.0 
├─┬ connect-assets@2.1.9 
│ ├── connect-file-cache@0.2.4 
│ ├── mime@1.2.2 
│ ├─┬ snockets@1.3.4 
│ │ ├── dep-graph@1.0.1 
│ │ └── uglify-js@1.0.7 
│ └── underscore@1.1.7 
├─┬ express@2.5.8 
│ ├─┬ connect@1.8.6 
│ │ └── formidable@1.0.9 
│ ├── mime@1.2.4 
│ ├── mkdirp@0.3.0 
│ └── qs@0.4.2 
├── express-messages@0.0.2 
├── gravatar@1.0.6 
├─┬ jade@0.22.1 
│ ├── commander@0.5.2 
│ └── mkdirp@0.3.0 
├── moment@1.5.1 
├─┬ mongoose@2.5.13 
│ ├── hooks@0.2.0 
│ └─┬ mongodb@0.9.9-7 
│   └── bson@0.0.4 
├── openid@0.4.1 
├─┬ pygments@0.1.2 
│ └── underscore@1.3.1 
├─┬ rss@0.0.3 
│ ├── logging@2.0.16 
│ └── xml@0.0.7 
├─┬ stylus@0.25.0 
│ ├── cssom@0.2.3 
│ ├── debug@0.6.0 
│ └── mkdirp@0.3.1 
├── uglify-js@1.2.6 
└── validator@0.4.5 

Expressが使われています。MongoDBのODMにはMongooseです。エラー表示やステータス表示にexpress-message。connect-assetsで、Rails Asset PipelineっぽくCSSやらJSやらまとめているようです。

server.coffeeを見てみます。

express = require 'express'
app = module.exports = express.createServer()

require('./config/config') app 
require('./config/routes') app 

app.listen 3000
console.log "coffee-box server listening on port #{app.address().port} " +
  "in #{app.settings.env} mode"

Expressを使っています。ConfigとRouterがあるみたい。

ルータを見ていきます。

config/routes.coffee(一部)

module.exports = (app) ->

  # get controllers from app settings
  controllersGetter    = app.settings.controllersGetter
  PostsController      = controllersGetter.getPostsController     app
  CommentsController   = controllersGetter.getCommentsController  app
  SessionController    = controllersGetter.getSessionController   app
  DashboardController  = controllersGetter.getDashboardController app

  # middleware for finding all posts published as individual pages
  findPages = PostsController.findPages
  # middleware for requiring login
  requireLogin = SessionController.requireLogin

  app.get '/'                    , findPages                , PostsController.index

  app.get  '/posts.:format?'     , findPages                , PostsController.index
  app.get  POST_SHOW_PATTERN     , findPages                , PostsController.show
  app.get  '/posts/new.:format?' , requireLogin , findPages , PostsController.new
  app.get  POST_EDIT_PATTERN     , requireLogin , findPages , PostsController.edit
  app.post '/posts.:format?'     , requireLogin             , PostsController.create
  app.put  POST_SHOW_PATTERN     , requireLogin             , PostsController.update
  app.del  POST_SHOW_PATTERN     , requireLogin             , PostsController.destroy
  app.post '/posts/preview'                                 , PostsController.preview

Controllerを登録して、ルーティングを決めています。例えば app.get '/'だったら、PostControllerのindex関数にルーティングされていることがわかります。

Postコントローラを見ていきます。

post_controller.coffee(一部)

    index: (req, res, next) ->
      # check pagination param: /posts/?page=2
      pageNo = parseInt(req.query['page'], 10) or 1

      POSTS_PER_PAGE = 5
      Post.countPostPages POSTS_PER_PAGE, (err, totalPages) ->
        Post.getPostsOfPage pageNo, POSTS_PER_PAGE, (err, posts) ->
          return res.redirect '500' if err?
          res.render 'posts/index'
            posts:      posts
            pageNo:     pageNo
            totalPages: totalPages

Post.getPostsOfPage がモデルを呼び出しているところ。res.renderでViewのposts/index.jadeにデータを投げ込んでレンダリングしています。

Postモデルを見ていきます。

app/models/post.coffee

async    = require 'async'
mongoose = require 'mongoose'
Schema   = mongoose.Schema

{markdown} = require('../../lib/markdown')
{makeTagList} = require('../../lib/taglist')

{CommentSchema} = require('./comment')

PostSchema = new Schema
  title:
    type: String
    required: true
  content:
    type: String
  rawContent:
    type: String
  slug:
    type: String
    required: true
    unique: true
  comments:
    type: [CommentSchema]

(中略)

PostSchema.statics.getPostsOfPage = (pageNo, postsPerPage, callback) ->
  @countPostPages postsPerPage, (err, count) =>
    return callback err, null if err?
    query =
      public: true
      asPage: false
    options =
      skip:   (pageNo - 1) * postsPerPage
      limit:  postsPerPage
      sort:   [['createdAt', 'desc']]
    @find query, {}, options, callback

mongooseを使ってスキーマを作っています。getPostsOfPage メソッドで、MongoDbにクエリを投げています。

Postのindexビューを見ていきます。

app/views/posts/index.jade(一部)

// entry list
ul.unstyled#entry-list
  each post in posts
    li!= partial('show', { locals: { post: post } })

(略)

Postコントローラの、res.renderでPostモデルから取得したデータを postsに入れています。jadeでループさせて表示させています。個々のPostデータの表示には、パーシャルを使って show.jade で表示させています。

app/views/posts/show.jade

article.entry.post
  != messages()
  header.entry-header
    h2.entry-title
      a(href=postPath(post))= post.title
    .entry-meta
      .entry-day= postDay(post)
      .entry-month= postMonth(post)
  .entry-content
    != post.content 
        
  != partial('comments/comments', { post: post, comments: post.comments })

全体的な流れはこんな感じです。

CoffeeBoxのコードはMVCでの組み方がよくわかります。ブログではログインの方法やセッションの持たせ方、設定などの方法、Stylusでの組み方、Assetの使い方についても理解しやすいです。

まだ改善できるところもありますし、CoffeeBoxは、コールドリーディングにはちょうどいい素材かもしれません。これがすべてではありませんが、脱初心者を目指す方はぜひ。

2012年3月14日水曜日

Twitter生まれの軽量なMVCフレームワーク「Matador」を試してみた

Matadorは、TwitterのOBが開発したNode.jsのMVCフレームワークです。ExpressにMVCの手法を取り入れたような、シンプルで軽量なフレームワークになっています。

インストールからアプリの雛形作成、起動まで。

$ npm install -g matador
$ npm init sample
$ cd sample
$ npm install
$ node server.js
matador running on port 3000

と、まあ、ここまでは簡単です。

少し構造を見てみます。

依存パッケージ

$ npm ls
/Users/inouetomoyuki/Dropbox/Projects/node/sample
└─┬ matador@1.0.11-beta 
  ├── colors@0.6.0-1 
  ├─┬ express@2.5.8 
  │ ├─┬ connect@1.8.5 
  │ │ └── formidable@1.0.9 
  │ ├── mime@1.2.4 
  │ ├── mkdirp@0.3.0 
  │ └── qs@0.4.2 
  ├── hogan.js@2.0.0 
  ├── klass@1.2.2 
  ├─┬ optimist@0.3.1 
  │ └── wordwrap@0.0.2 
  ├── uglify-js@1.2.5 
  └── valentine@1.5.1 

Express, Hogan, Klassを使っています。

アプリ作成直後のディレクトリ構造

$ tree app
server.js
node_modules/
app
├── config
│   ├── development.js
│   ├── production.js
│   └── routes.js
├── controllers
│   ├── ApplicationController.js
│   └── HomeController.js
├── models
│   ├── ApplicationModel.js
│   └── BaseModel.js
├── public
│   └── css
│       ├── directory.css
│       └── main.css
└── views
    ├── 404.html
    ├── admin
    │   ├── index.html
    │   └── partials
    │       └── helloworld.html
    ├── directory.html
    ├── index.html
    ├── layout.html
    └── partials
        └── helloworld.html

model, view, controller できちんと分かれていますね。シンプルです。

MongoDBを使って、タイトルと本文を登録するアプリを作ってみます。

まずはHelloWorldっぽいのを削除します。

$ app/controllers/HomeController.js
$ app/views/index.html
$ app/views/partials/helloworld.html

MongoDBはググってインストールして起動させておきましょう。

mongoose, mongodbをインストールします。

$ npm install mongoose
$ npm install mongodb

mongoを設定します。

app/models/ApplicationModel.js

module.exports = function (app, config) {
  return app.getModel('Base', true).extend(function() {
    this.mongo = require('mongodb')
    this.mongoose = require('mongoose')
    this.Schema = this.mongoose.Schema
    this.mongoose.connect('mongodb://localhost/madador')
  })  
}

scaffold機能でmodelとcontrollerの雛形を作成します。

$ madator controller Post
$ madator model Post

雛形にアクションを追加していきます。

app/models/PostModel.js

module.exports = function (app, config) {
  
  return app.getModel("Application", true).extend(function() {
      this.DBModel = this.mongoose.model('Post', new this.Schema({
          title: {type: String, require:true, trim:true }
        , body: {type: String, require:true, trim:true }
      }))
  })
  .methods({
    save: function(title, body, callback) {
      var post = new this.DBModel({
          title: title
        , body: body
      })
      post.save(callback)
    }
  , index: function(callback) {
      this.DBModel.find(callback)
    }
  })
}

app/controllers/PostController.js

module.exports = function (app, config) {
  
  return app.getController("Application", true).extend(function() {
    this.viewFolder = 'posts' // まだ動作しない模様
  })      
  .methods({
    index: function (req, res) {
      var PostModel = app.getModel('Post', true)
      var model = new PostModel()
      var _self = this
      model.index(function(err, posts) {
        if(err) throw err;
        _self.render(res, 'index', {
          posts: posts
        })
      })
    }
  , form: function(req, res) {
      this.render(res, 'new', {})
    }
  , create: function(req, res) {
      var PostModel = app.getModel('Post', true)
      var model = new PostModel()
      var _self = this;
      model.save(req.body.title, req.body.body, function(err) {
        if(err) throw err;
        res.redirect('/')
      })
    }
  })
}

ビューを作ります。登録フォームと一覧だけ。

app/views/index.html

<table border="1">
<tr>
<td>タイトル</td>
<td>一言</td>
</tr>     
  
{{#posts}} 
<tr>  
  <td><b>{{title}}</b></td>
<td>{{body}}</td> 
</tr> 
{{/posts}}
</table>
<a href="/posts/new">新規投稿</a>

app/views/new.html

<form action="/posts/create" method="post">
<label>タイトル</label><br />
<input type="input" name="title"><br />
<label>本文</label><br />
<textarea name="body"></textarea><br />
<input type="submit" value="登録">

</form>

ルーティングを定義します。

app/config/routes.js

module.exports = function (app) {
  return { 
    root: [
       ['get', '/', 'Post', 'index']
     ,  ['get', '/posts', 'Post', 'index']
     ,  ['get', '/posts/new', 'Post', 'form']
     ,  ['post', '/posts/create', 'Post', 'create']
    ]
  }
}

起動してみます。

http://localhost:3000/posts/new

http://localhost:3000/

viewsディレクトリ内をposts/new.htmlのように配置するには、PostController のコンストラクタに this.viewFolder = "posts" みたいにするそうですが、まだ動作しないようです。GitHub Issue。

Matadorは Tower.jsに比べるてシンプルなので理解しやすいですね。CoffeeScriptに対応しないかな。

追記

MatadorはCoffeeScriptに対応しました。対応方法は、[Node.js] Matador+CoffeeScriptの環境を構築する をご覧下さいませ。

2012年2月25日土曜日

CoffeeScriptとExpressとMongoDbとMochaでNode.jsするメモ

巷ではCoffeeScriptが流行っているそうで。ExpressとMongoDb、テストにMochaを使った定型文的なメモ。

インストールはこんな感じで。

$ sudo npm install -g coffee-script
$ sudo npm install -g js2coffee
$ express sample
$ cd sample && npm install
$ npm install mocha
$ npm install mongoose

expressで出来たテンプレをcoffeeに変換。


$ js2coffee app.js > app.coffee
$ js2coffee routes/index.js > app.coffee

Mochaのテスト。全文です。本来はコツコツやっていきませう。

test/routes-test.coffee

routes = require "../routes/index"
mongoose = require "mongoose"
Post = require "../models/Post"
require "should"
  
describe "routes", ->
  req = 
    params: {} 
    body: {}
  res =
    redirect: (route) ->
      #do nothing
    render: (view, vars)->
      #do nothing
  before (done) ->
    mongoose.connect 'mongodb://localhost/blog', ->
      Post.remove done

  describe "index", ->
    it "should display index with posts", (done) ->
      res.render = (view, vars) ->
          view.should.equal "index"
          vars.title.should.eql "ぶろぐ"
          vars.posts.should.eql []
          done()
      routes.index(req, res)

  describe "new post", ->
    it "should display the add post page", (done) ->
      res.render = (view, vars) ->
        view.should.equal "add_post"
        vars.title.should.equal "あたらしい投稿"
        done()
      routes.newPost(req, res)
    it "should add a new post when posted to", (done) ->
      req.body.post =
        title: "たいとるです"
        body: "ほんぶんです"

      routes.addPost req, redirect:(route) ->
        route.should.eql "/"
        routes.index req, render: (view, vars) ->
          view.should.equal "index"
          vars.posts[0].title.should.eql "たいとるです"
          vars.posts[0].body.should.eql "ほんぶんです"
          done()

メイン

app.coffee

express = require("express")
routes = require("./routes")
mongoose = require('mongoose')

app = module.exports = express.createServer()
app.configure ->
  app.set "views", __dirname + "/views"
  app.set "view engine", "jade"
  app.use express.bodyParser()
  app.use express.methodOverride()
  app.use app.router
  app.use express.static(__dirname + "/public")

app.configure "development", ->
  mongoose.connect 'mongodb://localhost/blog-dev'
  app.use express.errorHandler(
    dumpExceptions: true
    showStack: true
  )

app.configure "production", ->
  mongoose.connect 'mongodb://localhost/blog-prod'
  app.use express.errorHandler()

app.get "/", routes.index
app.get "/post/new", routes.newPost
app.post "/post/new", routes.addPost
app.get "/post/:id", routes.viewPost
app.listen 3000
console.log "Express server listening on port %d in %s mode", app.address().port, app.settings.env

ルーティング

routes/index.coffee

Post = require '../models/Post'

module.exports =
  index : (req, res) ->
    Post.find {}, (err, posts) ->
      res.render "index",
        title: "ぶろぐ"
        posts: posts
  
  newPost : (req, res) ->
    res.render "add_post", title:"あたらしい投稿"
  
  addPost : (req, res) ->
    new Post(req.body.post).save ->
      res.redirect "/"
  
  viewPost: (req, res) ->
    Post.findById req.params.id, (err, post) ->
      res.render 'post', post: post, title: post.title

モデル

models/Post.coffee

mongoose = require 'mongoose'

Post = new mongoose.Schema(
  title: String,
  body: String
)     
        
module.exports = mongoose.model 'Post', Post

ビュー

views/layout.jade

!!!5  
html    
  head  
    title= title
    link(rel="stylesheet", href="http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css")
    style(type="text/css")
      #content {padding-top: 60px; }
  body    
    .topbar-wrapper
      .topbar
        .topbar-inner
          .container
            h3: a(href="/")= title
            ul.nav
              li: a(href="/post/new") あたらしい投稿
    #content.container!=body

views/index.jade

- each post in posts
  .page-header
    h1  
      a(href="/post/#{post.id}")= post.title
  .content!=post.body

views/add_post.jade

form(method="post", action="/post/new")
  fieldset
    legend=title
    .clearfix
      label(for="title") たいとる
      .input
        input.xlarge#title(type="text", name="post[title]")
    .clearfix
      label(for="post") ないよう
      .input
        textarea#post.xxlarge(name="post[body]", rows="3")
    .actions
      input.btn.primary(type="submit", value="こうかい!")
      |  
      a.btn(href="/") やめた

views/post.jade

.page-header
  h1= post.title
.content!=post.body

実行


$ coffee app.coffee

次はCoffeeKupも使ってみようと思います。Coffeeで統一。

2012年1月14日土曜日

NodeでMongoDBを使って連絡帳アプリを作る


MongoDBはドキュメント指向のNoSQLデータベースです。Express、MongoDBを組み合わせて連絡帳ウェブアプリケーションを構築してみます。

システム構成

  • Mac OS X Lion
  • Node 0.6.7
  • MongoDB 2.0.2
  • フレームワーク: Express
  • HTMLテンプレート: jade

アクション一覧

アクション名URLメソッド説明
トップページ/GET一覧画面にリダイレクトします。
一覧画面表示/addressbookGET連絡先の一覧を表示します。
連絡先を選択すると詳細を表示します。
詳細画面表示/addressbook/show/:idGET連絡先の詳細を表示します。
編集画面表示/addressbook/edit/:idGET連絡先の編集フォームを表示します。
更新/addressbook/update/:idPOST連絡先を更新し、詳細に戻ります。
作成画面表示/addressbook/addGET連絡先の作成フォームを表示します。
作成/addressbook/insertPOST新しい連絡先を挿入し、
連絡先一覧に戻ります。
削除/addressbook/delete/:idGET連絡先を削除し、一覧に戻ります。

目次

  1. MongoDBのインストール
  2. Expressのインストールと雛形作成
  3. モデルの作成
  4. コントローラの作成
  5. ビューの作成

MongoDBをダウンロードしてインストールします。

$ curl -O http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-2.0.2.tgz .
$ rm mongodb-osx-x86_64-1.6.5.tgz 
$ tar -xzvf mongodb-osx-x86_64-2.0.2.tgz 
x mongodb-osx-x86_64-2.0.2/
x mongodb-osx-x86_64-2.0.2/bin/
x mongodb-osx-x86_64-2.0.2/bin/bsondump
x mongodb-osx-x86_64-2.0.2/bin/mongo
x mongodb-osx-x86_64-2.0.2/bin/mongod
x mongodb-osx-x86_64-2.0.2/bin/mongodump
x mongodb-osx-x86_64-2.0.2/bin/mongoexport
x mongodb-osx-x86_64-2.0.2/bin/mongofiles
x mongodb-osx-x86_64-2.0.2/bin/mongoimport
x mongodb-osx-x86_64-2.0.2/bin/mongorestore
x mongodb-osx-x86_64-2.0.2/bin/mongos
x mongodb-osx-x86_64-2.0.2/bin/mongosniff
x mongodb-osx-x86_64-2.0.2/bin/mongostat
x mongodb-osx-x86_64-2.0.2/bin/mongotop
x mongodb-osx-x86_64-2.0.2/GNU-AGPL-3.0
x mongodb-osx-x86_64-2.0.2/README
x mongodb-osx-x86_64-2.0.2/THIRD-PARTY-NOTICES
$ sudo mv mongodb-osx-x86_64-2.0.2/bin/* /usr/local/bin/
Password:
$ rm -fr mongodb-osx-x86_64-2.0.2 mongodb-osx-x86_64-2.0.2.tgz 

データ保存用のディレクトリを作成します。

$ mkdir ~/Library/MongoDB_Data

起動して動作を確認します。(--dbpathは絶対パスです。)

$ mongod --dbpath=/Users/inouetomoyuki/Library/MongoDB_Data/ &
[1] 86938
$ Sat Jan 14 16:21:40 [initandlisten] MongoDB starting : pid=86938 port=27017 dbpath=/Users/inouetomoyuki/Library/MongoDB_Data/ 64-bit host=imonshin.globals.jp
Sat Jan 14 16:21:40 [initandlisten] db version v2.0.2, pdfile version 4.5
Sat Jan 14 16:21:40 [initandlisten] git version: 514b122d308928517f5841888ceaa4246a7f18e3
Sat Jan 14 16:21:40 [initandlisten] build info: Darwin erh2.10gen.cc 9.6.0 Darwin Kernel Version 9.6.0: Mon Nov 24 17:37:00 PST 2008; root:xnu-1228.9.59~1/RELEASE_I386 i386 BOOST_LIB_VERSION=1_40
Sat Jan 14 16:21:40 [initandlisten] options: { dbpath: "/Users/inouetomoyuki/Library/MongoDB_Data/" }
Sat Jan 14 16:21:40 [initandlisten] journal dir=/Users/inouetomoyuki/Library/MongoDB_Data/journal
Sat Jan 14 16:21:40 [initandlisten] recover begin
Sat Jan 14 16:21:40 [initandlisten] info no lsn file in journal/ directory
Sat Jan 14 16:21:40 [initandlisten] recover lsn: 0
Sat Jan 14 16:21:40 [initandlisten] recover /Users/inouetomoyuki/Library/MongoDB_Data/journal/j._0
Sat Jan 14 16:21:40 [initandlisten] recover cleaning up
Sat Jan 14 16:21:40 [initandlisten] removeJournalFiles
Sat Jan 14 16:21:40 [initandlisten] recover done
Sat Jan 14 16:21:40 [websvr] admin web console waiting for connections on port 28017
Sat Jan 14 16:21:40 [initandlisten] waiting for connections on port 27017

別のターミナルを開いて、MongoDBクライアントを起動してみます。

$ mongo
MongoDB shell version: 2.0.2
connecting to: test
Sat Jan 14 16:23:08 [initandlisten] connection accepted from 127.0.0.1:49329 #1
>

MongoDBのコンソールに入りました。起動しているようです。show dbsでデータベースを一覧します。

> show dbs
local (empty)

データベースはまだ存在しません。以下のようなコマンドを打ってみます。

> db.addressbook.save({'name':'Miku Hatsune'});
> db.addressbook.find();
{ "_id" : ObjectId("4f1130033a59d9bef8402fc7"), "name" : "Miku Hatsune" }
> 

コレクションaddressbookにデータが登録されています。

> show dbs;
local (empty)
test 0.203125GB
> 

testというデータベースができています。

exitコマンドでターミナルに戻ります。mongodは起動したままにして、アプリの開発に進みます。(mongodを終了するにはkill -9コマンドを使用します)


Expressとmongooseのインストール

$ sudo npm install -g express
$ express addressbook
$ cd addressbook && npm install
$ npm install mongoose
$ mkdir models
$


モデルContactの作成

models/contact.jsというファイル名でContact(連絡先)のモデルを作成します。

models/contact.js

var mongo = require('mongoose');
mongo.connect('mongodb://localhost/addressbook');

var Schema = mongo.Schema;

var Contact = mongo.model('contacts', new Schema({
    name: String,
    address: String,
    createAt: {type: Date, default: Date.now}
    })  
);

module.exports = Contact;

app.jsにコードを追加してmodels/contactを使えるようにします。

app.js

var express = require('express')
  , routes = require('./routes')
  , contact = require('./models/contact');


コントローラの作成

app.jsに記述していきます。アクション毎に書いていくのが良いのですが、ここでは一気に掲載します。

app.js

// ホーム
app.get('/', function(req, res) {
   res.redirect('/addressbook/list'); 
});

// 一覧表示
app.get('/addressbook/list', function(req, res) {
    contact.find({}, function(err, contacts) {
        if(err) throw err;
        res.render('list', {title:'Address Book', contacts:contacts});
    }); 
});

// 詳細表示
app.get('/addressbook/show/:id', function(req, res) {
    contact.findOne({_id:req.param('id')}, function(err, contact) {
        if(err) throw err;
        res.render('show', {title:'Contact', contact:contact});
    }); 
});

// 編集表示
app.get('/addressbook/edit/:id', function(req, res) {
    contact.findOne({_id:req.param('id')}, function(err, contact) {
        if(err) throw err;
        res.render('edit', {title:'Contact(Edit)', contact:contact});
    }); 
});

// 新規作成表示
app.get('/addressbook/new', function(req, res) {
    res.render('new', {title:'Contact(New)'});
});

// 更新アクション
app.post('/addressbook/update/:id', function(req, res) {
    contact.findById(req.param('id'), function(err, contact) {
        if(!contact)
            throw err;
        else {
            contact.name = req.param('name');
            contact.address = req.param('address');
            contact.save(function(err) {
                if(err)
                    throw err;
                else
                    res.redirect('/addressbook/show/' contact._id);
            });
        }
    });
});

// 追加アクション
app.post('/addressbook/insert', function(req, res) {
    var con = new contact();
    con.name = req.param('name');
    con.address = req.param('address');
    con.save(function(err) {
        if(err) throw err;
        res.redirect('/addressbook/list');
    });
});

// 削除アクション
app.get('/addressbook/delete/:id', function(req, res) {
    contact.remove({_id:req.param('id')}, function(err) {
        if(err) throw err;
        res.redirect('/addressbook/list');
    });
});



ビューの作成

views/list.jade

table(border='1')
    - for (var i=0; i<contacts.length; i  )
        tr
            td: a(href='/addressbook/show/'   contacts[i]._id)= contacts[i].name
            td= contacts[i].address
p
    a(href='/addressbook/new')
        新規作成

views/show.jade

h2 氏名
p= contact.name
h2 住所
p= contact.address
p
    a(href='/addressbook/edit/'   contact._id)
        編集
p
    a(href='/addressbook/delete/'   contact._id)
        削除

views/edit.jade

form(action='/addressbook/update/'   contact._id, method='post')
    h2 氏名
    input#name(name='name', type='text', value=contact.name)
    h2 住所
    input#address(name='address', type='text', value=contact.address)
    p
        input#submit(type='submit', value='保存')

views/new.jade

form(action='/addressbook/insert', method='post')
    h2 氏名
    input#name(name='name', type='text')
    h2 住所
    input#address(name='address', type='text')
    input#submit(type='submit', value='保存')

動作確認

http://127.0.0.1:3000 にアクセスして動作を確認します。

一覧画面

新規作成画面

一覧画面(追加後)

詳細画面

編集画面