本文為 Lidemy [BE201] > [ORM 與 Sequelize] > [改造留言板系統] 的學習筆記,學習如何使用後端好朋友們 Express、ORM & Sequelize 打造留言板
零、內容摘要
前置作業 — 安裝環境
關聯 models
新增 controllers、views 資料夾,參考 後端好朋友 Express 基本介紹與操作
把留言板改成使用 Sequelize 的版本
一、前置作業設定
1. 前置作業
a. 初始化資料夾 $ npm init
,接著全按 enter
b. 建 express 環境 + middlewares
$ npm install ejs body-parser express-session connect-flash bcrypt
c. 利用 Sequelize 建 ORM 環境
$ npm install --save sequelize mysql2
d. migrations
$ npm install --save-dev sequelize-cli
$ npx sequelize-cli init
e. 改 config 檔案 development
f. 建立 model
$ npx sequelize-cli model:generate --name User --attributes username:string,password:string,nickname:string
$ npx sequelize-cli model:generate --name Comment --attributes content:text
註:UserId 應該要在這裡也一起建,但不確定是要寫 UserId:integer
這樣嗎?
後來有查到這個參考資料:Data Types
g. Running Migrations
$ npx sequelize-cli db:migrate
2. models 加上關聯
static associate(models) {
User.hasMany(models.Comment)
}
static associate(models) {
Comment.belongsTo(models.User)
}
3. 把之前 controllers 的內容改一改
// comment.js
const db = require('../models')
const Comment = db.Comment
const commentController = {
add: (req, res) => {
const { username } = req.session
const { content } = req.body
if (!username || !content) {
return res.redirect('/')
}
},
index: (req, res) => {
res.render('index', {
comments: []
})
},
delete: (req, res) => {
},
update: (req, res) => {
res.render('update', {
comment: {}
})
},
handleUpdate: (req, res) => {
}
}
module.exports = commentController
// user.js
const bcrypt = require('bcrypt')
const saltRounds = 10
const db = require('../models')
const User = db.User
const userController = {
login: (req, res) => {
res.render('user/login')
},
handleLogin: (req, res, next) => {
const { username, password, nickname } = req.body
if (!username || !password) {
req.flash('errorMessage', 'Please fill in all the required fields.')
return next()
}
User.findOne({
where: {
username
}
}).then(user => {
if (!user) {
req.flash('errorMessage', 'invalid user')
return next()
}
bcrypt.compare(password, user.password, function(err, isSuccess) {
if (err || !isSuccess) {
req.flash('errorMessage', 'invalid password')
return next()
}
req.session.username = user.username
res.redirect('/')
});
}).catch(err => {
req.flash('errorMessage', err.toString())
return next()
})
},
register: (req, res) => {
res.render('user/register')
},
handleRegister: (req, res, next) => {
const { username, password, nickname } = req.body
if (!username || !password || !nickname) {
req.flash('errorMessage', 'Please fill in all the required fields.')
return next()
}
bcrypt.hash(password, saltRounds, function(err, hash) {
if (err) {
req.flash('errorMessage', 'user exists')
return next()
}
User.create({
username,
password: hash,
nickname
}).then(() => {
req.session.username = username
res.redirect('/')
}).catch((err) => {
req.flash('errorMessage', 'user exists')
return next()
})
});
},
logout: (req, res) => {
req.session.username = null
res.redirect('/')
}
}
module.exports = userController
改到這裡可以先跑跑看,測試註冊跟登入功能都成功了。
4. 去 migrations 裡面的 comments 新增 UserId,重跑 migrations
$ npx sequelize-cli db:migrate:undo
這樣 Comments 的表格會全部不見,然後再跑一次 migrations
$ npx sequelize-cli db:migrate
二、開始實作留言板 — 留言部份 12'50"
1. 新增留言
// controllers > comment.js
add: (req, res) => {
const { userId } = req.session
const { content } = req.body
if (!userId || !content) {
return res.redirect('/')
}
Comment.create({
content,
UserId: userId
}).then(() => {
res.redirect('/')
})
},
除了修改新增留言功能以外,在 handleLogin & handleRegister 都要在抓到使用者時,一並拿到 req.session.userId = user.id
2. 抓取所有留言
// controllers > index.js
index: (req, res) => {
Comment.findAll({
include: User
}).then((comments) => {
res.render('index', {
comments
})
})
},
除了 index 顯示留言以外,在 views > index.ejs 裡面跟使用者有關的,都要用到 comment.User.username or comment.User.nickname,因為 User 是從 model 裡面來的
3. 刪除留言
delete: (req, res) => {
Comment.findOne({
where: {
id: req.params.id,
UserId: req.session.userId
}
}).then((comment) => {
return comment.destroy()
}).then(() => {
res.redirect('/')
}).catch(() => {
res.redirect('/')
})
},
4. 編輯留言
update: (req, res) => {
Comment.findOne({
where: {
id: req.params.id
}
}).then((comment) => {
res.render('update', {
comment
})
})
},
handleUpdate: (req, res) => {
Comment.findOne({
where: {
id: req.params.id,
UserId: req.session.userId
}
}).then((comment) => {
return comment.update({
content: req.body.content
})
}).then(() => {
res.redirect('/')
}).catch(() => {
res.redirect('/')
})
}
5. 留言由新到舊排序
在 findAll 裡面加上 order
index: (req, res) => {
Comment.findAll({
include: User,
order: [
['updatedAt', 'DESC']
]
}).then((comments) => {
res.render('index', {
comments
})
})
},
三、心得
使用這個方法好方便喔,跟之前第九週、第十一週比起來,簡直有天壤之別,就是一種工業革命大躍進的感覺,而且程式碼變得很好讀又簡潔❤️