N予備校のプログラミング入門メモ17
はじめに
妹とデートしてきた。
4章 実践サーバーサイドプログラミング
18.予定の一覧の表示
講座用のプロジェクトをcloneしてnpm start
したところ、DBのエラーが出た。
Unhandled rejection SequelizeDatabaseError: column "scheduleId" does not exist at Query.formatError (/home/vagrant/workspace/schedule-arranger-4018/node_modules/sequelize/lib/dialects/postgres/query.js:357:14) at Query.<anonymous> (/home/vagrant/workspace/schedule-arranger-4018/node_modules/sequelize/lib/dialects/postgres/query.js:88:19) at emitOne (events.js:96:13) at Query.emit (events.js:188:7) at Query.handleError (/home/vagrant/workspace/schedule-arranger-4018/node_modules/pg/lib/query.js:108:8) at Connection.<anonymous> (/home/vagrant/workspace/schedule-arranger-4018/node_modules/pg/lib/client.js:171:26) at emitOne (events.js:96:13) at Connection.emit (events.js:188:7) at Socket.<anonymous> (/home/vagrant/workspace/schedule-arranger-4018/node_modules/pg/lib/connection.js:109:12) at emitOne (events.js:96:13) at Socket.emit (events.js:188:7) at readableAddChunk (_stream_readable.js:176:18) at Socket.Readable.push (_stream_readable.js:134:10) at TCP.onread (net.js:547:20)
まだ何もいじっていないがscheduleId
が存在しないという旨のエラーのようなので一応コードを確認するも特に問題がない。ということでDBの方が不整合になっているのかと思ってpsql
でdrop database
してcreate database
したところ、今度はちゃんと起動した。前回の写経で変な風にtypoしたくせにつじつまが合って起動できてしまったといったところか。
index.jade
にログイン/ログアウトボタンを追加してRouterオブジェクトのindex.js
でテンプレートにユーザ情報のオブジェクトを渡すように修正。
新規予定作成画面のテンプレート、そこからPOSTを受け取るRouterオブジェクトを実装する。認証を確認するハンドラ関数も実装しておき、Routerのget
関数などの第二引数にしていすることで呼び出し時に認証が確認されるようにできる。
'use strict'; function ensure(req, res, next) { if (req.isAuthenticated()) { return next(); } res.redirect('/login'); } module.exports = ensure;
const authenticationEnsurer = require('./authentication-ensurer'); router.get('/new', authenticationEnsurer, (req, res, next) => { res.render('new', { user: req.user }); });
上記のようにするとログインしていない状態で予定作成画面/new
にアクセスするとログイン画面にリダイレクトされる。
予定作成に使うUUIDを実装する。
yarn add node-uuid@1.4.7
インストールしたらv4
という関数を呼び出すとUUID文字列を取得できる。
予定と候補を保存する機能を実装する。sequelizeオブジェクトのbulkCreate
関数で複数のデータをDBに保存できる。
Promiseについて。そういえば解説されてなかった。非同期でよく見るやつ、というイメージだったけど解説もだいたいそんな感じだった(失礼)。
index.jade
に自分で作った予定の一覧を表示するように修正。each in
を使ってテーブルの行をループで表示する。Routerオブジェクトからテンプレートに予定の一覧を渡すのを忘れずにやる。以前もやったfindAll
関数を使って自分が作った予定一覧を取得する。
/schedule/:scheduleId
を実装する。:scheduleId
はUUIDの文字列。
RouterオブジェクトのfindOne
関数は1行を取得する。
ここでinclude
というのが急に出てきた。(忘れてるだけかもしれない)
Schedule.findOne({ include: [ { model: User, attributes: ['userId', 'username'] }],
事前に Schedule.belongsTo(User, {foreignKey: 'createdBy'});
と従属の設定をしているのでこうやってユーザー情報が取得できる、というもののようだ。たぶん。user
プロパティにユーザー情報が設定される。
練習問題で予定が表示されることのテストを書いたが、そこでexpect
関数でテストしたあとにend
関数内でテストで作成したデータを削除する処理が書かれている。
it('予定が作成でき、表示される', (done) => { User.upsert({ userId: 0, username: 'testuser' }).then(() => { request(app) .post('/schedules') .send({ scheduleName: 'テスト予定1', memo: 'テストメモ1\r\nテストメモ2', candidates: 'テスト候補1\r\nテスト候補2\r\nテスト候補3' }) .expect('Location', /schedules/) .expect(302) .end((err, res) => { let createdSchedulePath = res.headers.location; request(app) .get(createdSchedulePath) .expect(/テスト予定1/) .expect(/テストメモ1/) .expect(/テストメモ2/) .expect(/テスト候補1/) .expect(/テスト候補2/) .expect(/テスト候補3/) .expect(200) .end((err, res) => { // テストで作成したデータを削除 let scheduleId = createdSchedulePath.split('/schedules/')[1]; Candidate.findAll({ where: { scheduleId: scheduleId } }).then((candidates) => { candidates.forEach((c) => { c.destroy(); }); Schedule.findById(scheduleId).then((s) => { s.destroy(); }); }); if (err) return done(err); done(); }); }); }); });
19.出欠の表示と更新
2次元のデータ構造についての話。特別新しい話はなかった気がする。ApplicationオブジェクトにRouterオブジェクトを設定する際、同じパスに対して複数のRouterオブジェクトを設定しているのはこういうのもあるのかという感じ。
20.コメントの表示と更新
出欠の更新、コメントの更新APIを実装して、jQueryとwebpackを入れてAJAXでそれぞれが更新できるようにした。
一時中断してたけど日をまたいだので一旦投稿。