Express 實作留言板:新增會員、登入、留言、編輯及刪除


Posted by Christy on 2022-01-13

本文為 Lidemy [BE201] 裡面的影片,[超重要觀念:Middleware] 之 [再做一個超簡易留言板,只要有新增就好] 到 [把留言板變得更完整] 之 [實作編輯功能] 的實作過程,主要以 express 練習做一個有新增會員、登入、留言、編輯及刪除功能的留言板。

零、內容摘要

1. 新增留言流程:開 table → views 做首頁畫面的留言輸入框 → index.js 新增路由 → controllers → 先把 models 寫好再回頭寫 controllers → controllers → views

2. What I have learned for now 到目前為止的概念有:

a. 大致流程就是:

table → routes → the methods in controllers → models → controllers → views

b. 其實也沒有什麼所謂固定的流程吧,但基本上就是「做了這個才能做下一步」,這樣做比較順暢而已。

c. 剛在思考關於畫面,什麼時候可以拿到畫面或者何時該做畫面,畢竟畫面對我很重要,是一種視覺上的輔助,但是後端似乎著重在「資料」,是另一種思考模式

一、實作留言板新增功能

1. 開 table:

  • id

  • username in 32 length wiith varchar

  • content with Text

2. 新增路由

// index.js

const commentController = require('./controllers/comment')

app.get('/', commentController.index)

app.post('/comments', commentController.add)

3. controllers > comment.js

// controllers > comment.js

const commentModel = require('../models/comment')

const commentController = {
  add: (req, res) => {

  }
}

module.exports = commentController

4. models > comment.js

// models > comment.js

const db = require('../db')

const commentModel = {
  add: (username, content, cb) => {
    db.query(
      'insert into comments(username, content) values(?, ?)',
      [username, content],
      (err, results) => {
        if (err) return cb(err)
        cb(null)
      }
    );
  },
  // 讀取的等一下再寫
  get: (username, cb) => {
    // db.query(
    //   'SELECT * from users where username = ?', [username],
    //   (err, results) => {
    //     if (err) return cb(err)
    //     cb(null, results[0])
    //   }
    // );
  }
}

module.exports = commentModel

5. controllers > comment.js

裡面的 console.log() 是拿來 debug 用的

// controllers > comment.js

const commentModel = require('../models/comment')

const commentController = {
  add: (req, res) => {
    const { username } = req.session
    const { content } = req.body
    if (!username || !content) {
      console.log('err')
      return res.redirect('/')
    }
    commentModel.add(username, content, (err) => {
      console.log('err1', err)
      return res.redirect('/')
    })
  }
}

module.exports = commentController

6. 讀取留言

a. 來複習 sql query 吧

可以先在軟體裡面的 query 跑跑看:

// models > comment.js

getAll: (cb) => {
  db.query(
    `SELECT U.nickname, C.content
      FROM comments as C 
      LEFT JOIN users as U on U.username = C.username
      ORDER BY createdAt DESC
    `,
    (err, results) => {
      if (err) return cb(err)
      cb(null, results)
    }
  );
}

b. controllers 裡面新增一個 index 當作 method

// controllers > comment.js

index: (req, res) => {
  commentModel.getAll((err, results) => {
    if (err) {
      console.log(err)
    }
    res.render('index', {
      comments: results
    })
  })
}

c. views > index.ejs

<% comments.forEach(function(comment) { %>
  <div>
    <h2><%= comment.nickname %></h2>
    <p><%= comment.content %></p>
  </div>
<% }) %>

二、認真規劃一個留言板吧

1. 思考全貌

a. 刪除留言:利用 GET 方式,按下刪除按鈕,先把某一則留言刪掉,再導回首頁

GET /delete_comments/id → /

b. 編輯留言:按下編輯按鈕時,導到另一個編輯頁面;編輯完後按下 submit 回到首頁

GET /update_comments/id → form POST /update_comments/id → /

2. 規劃結構

開 table,通常會有:

  • id

  • username

  • content

  • createdAt

  • updatedAt

註:

a. createdAt:type → datetime; default → current_timestamp()

b. updatedAt 的時間搞不定,查到的資料應該是下面的設定,但是 sequel pro 一直報錯不給我改

updatedAt:type → datetime; default → current_timestamp()?; extra → on update CURRENT_TIMESTAMP

3. 實作刪除功能

a. comment.ejs 加上刪除按鈕:如果不是使用者的留言,就沒有刪除按鈕

<% if (username === comment.username) { %>
  <a href="delete_comments/<%= comment.id %>">delete</a>
<% } %>

b. 加上路由

app.get('/delete_comments/:id', commentController.delete)

註:記得 getAll 的 controller 裡面要加上 SELECT U.nickname, C.content, C.id, C.username 要拿到 id & username 才可以

c. controllers

delete: (req, res) => {
  commentModel.delete(req.session.username, req.params.id, err => {
    res.redirect('/')
  })
}

d. Models

delete: (username, id, cb) => {
  db.query(
    `DELETE FROM comments where id = ? AND username = ?`, [id, username],
    (err) => {
      if (err) return cb(err)
      cb(null)
    }
  );
}

4. 實作編輯功能

a. 首頁畫面,複製刪除的程式碼改成編輯,並且新增一個編輯頁面如下

註:少了一個等號,送出編輯後的內容抓不到

<h1>Edit Page</h1>
<form method="POST" action="/update_comments/<%= comment.id %>">
  <textarea name="content" id="" cols="30" rows="10"><%= comment.content %></textarea>
  <input type="submit">
</form>

b. 路由

app.get('/update_comments/:id', commentController.update)
app.post('/update_comments/:id', commentController.handleUpdate)

c. controllers 先寫個大概 update & handleUpdate

d. models 新增函式 get & delete

get: (id, cb) => {
  db.query(
    `SELECT U.nickname, C.content, C.id, C.username
      FROM comments as C 
      LEFT JOIN users as U on U.username = C.username
      WHERE C.id = ?
    `, [id],
    (err, results) => {
      if (err) return cb(err)
      cb(null, results[0] || {})
    }
  );
},

update: (username, id, content, cb) => {
  db.query(
    `UPDATE comments SET content = ? WHERE id = ? AND username = ?`,
    [content, id, username], 
    (err) => {
      if (err) return cb(err)
      cb(null)
    }
  );
}

e. controllers

update: (req, res) => {
  commentModel.get(req.params.id, (err, result) => {
    res.render('update', {
      comment: result
    })
  })
},

handleUpdate: (req, res) => {
  commentModel.update(req.session.username, req.params.id, req.body.content, err => {
    res.redirect('/')
  })
}

三、結論

1. 好像漸漸有手感了,可是又有一種模糊的感覺,就是大概知道怎麼做,但是要等實作好幾遍以後,才會有種確定每一項細節的踏實感。

2. 感覺後面學到 ORM 以後,又會是另一個世界,所以先繼續去學 ORM,之後再回頭看會比較好。










Related Posts

[JS Behind The Scene] 從 for loop 理解 scope 和 event loop 的運作機制

[JS Behind The Scene] 從 for loop 理解 scope 和 event loop 的運作機制

XSS lab (1)

XSS lab (1)

Command Line 基本指令

Command Line 基本指令


Comments