0
1

More than 3 years have passed since last update.

【ドットインストール】Express入門講座の仕様変更点【 #19 記事を更新/削除してみよう】

Last updated at Posted at 2020-06-10

はじめに

ドットインストールのExpress講座は最終更新日が2014年のままアーカイブされていて、講座内容そのままやってもうまくいかない箇所がある。

「» 19 記事を更新/削除してみよう」
の章では、Expressのmethod-overrideモジュールの仕様が変わっているため、POSTメソッドの書き換えができず、エラーが出てしまった。新しい仕様に対応した正しいやり方をメモしておく。

Expressの公式ドキュメントでは、Express3からExpress4にバージョンが変わって以降、仕様変更されたミドルウェア・システムがまとめられている。

「Express 4 への移行」
https://expressjs.com/ja/guide/migrating-4.html

※「method-overrideモジュール」とは
ブラウザを、HTTPのPUT,DELETEメソッドに対応させるためのモジュール。

Express では get、post、put、delete というHTTPリクエストを送れるが、ブラウザは get と post にしか対応していない。
「method-overrideモジュール」を読み込むと、ブラウザを put と delete に対応させることができる。

ドットインストールで作成するブログアプリのファイル構成

├── app.js
├── node_modules
├── package-lock.json
├── package.json
├── routes           //ルーティング処理
│   └── post.js 
└── views           //テンプレートエンジン
    ├── partials     //UIの共通パーツを別ファイル化
    │   ├── footer.ejs
    │   └── header.ejs
    └── posts
        ├── edit.ejs   //編集ページ
        ├── index.ejs  //記事タイトル一覧ページ(編集・削除ボタン付き)
        ├── new.ejs
        └── show.ejs

講座のままだとエラーになる箇所

・app.js

var express = require('express'),
    app = express(),
    post = require('./routes/post');

app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

// middleware
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride()); //Express3仕様の書き方(エラーの原因)

app.use(express.logger('dev'));
app.use(app.router);

// routing

app.get('/', post.index);
app.get('/posts/:id([0-9]+)', post.show);
app.get('/posts/new', post.new);
app.post('/posts/create', post.create);
app.get('/posts/:id/edit', post.edit);
app.put('/posts/:id', post.update);
app.delete('/posts/:id', post.destroy);

app.listen(3000);
console.log("server starting...");

・edit.ejs【編集ページ】

<%- include ('../partials/header'); %>
<h1>Edit</h1>
//HTMLにはputメソッドがないため、postメソッドをサーバー側で変更する
<form method="post" action="/posts/<%= id %>">
   <input type="text" name="title" value="<%= post.title %>">
   <input type="text" name="body" value="<%= post.body %>">

//以下の一文を入れるとputメソッドとして認識されるはず(実際にはPOSTメソッドと認識されエラーに)
   <input type="hidden" name="_method" value="put">

   <input type="hidden" name="id" value="<%= id %>">
   <input type="submit" value="更新">
</form>

<p><a href="/">Back to Top</a></p>
<%- include ('../partials/footer'); %>

・index.ejs【記事タイトル一覧&編集・削除ボタン】

<%- include ('../partials/header'); %>
<h1>Posts</h1>
<ul>
<% for (var i=0; i<posts.length; i++){ %>
<li>
    <a href="/posts/<%= i %>"><%= posts[i].title %></a>
    <a href="/posts/<%= i %>/edit">[Edit]</a>

//HTMLにはdeleteメソッドがないため、見せかけのコードで代用
    <form method="post" action="/posts/<%= i %>">
//以下の一文を入れるとdeleteメソッドとして認識されるはず(実際にはPOSTメソッドと認識されエラーに)
        <input type="hidden" name="_method" value="delete">

        <input type="hidden" name="id" value="<%= i %>">
        <input type="submit" value="削除">
    </form>
</li>
<% } %>
</ul>
<p><a href="/posts/new">Add new</a></p>
<%- include ('../partials/footer'); %>

method overrideの変更点

『Express公式ドキュメント method-override』( http://expressjs.com/en/resources/middleware/method-override.html )

「クエリ値を使用して上書きする(override using a query value)」
を参照

クエリ文字列の値を使用してメソッドをオーバーライドするには、methodOverride 関数の文字列引数にクエリ文字列キーを指定します。呼び出しを行うには、そのクエリ文字列キーの値としてオーバーライドされたメソッドを持つ URL に POST リクエストを送信します。クエリ値を使用するこの方法は、レガシーなブラウザをサポートしつつも新しいメソッドを使用しようとしている場合、通常はプレーンなHTML <form>要素と一緒に使用されます。

・javascript(サーバーサイド)


var express = require('express')
var methodOverride = require('method-override')
var app = express()

// override with POST having ?_method=DELETE
app.use(methodOverride('_method'))

・HTML(フロントエンド)

<form method="POST" action="/resource?_method=DELETE">
  <button type="submit">Delete resource</button>
</form>

Express4バージョンで実装

・app.js

const express = require('express');
const app = express();
//POSTで渡ってきたものをreq.resで取得するmiddlewareのためのモジュール (※bodyParserはExpress4では不要?未確認)
const bodyParser = require('body-parser');
const methodOverride = require('method-override');
//ルーティングを記述したファイルをモジュールとして読み込み
const post = require('./routes/post')

app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

//POSTで渡ってきたものをreq.resで取得するためのmiddleware
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended:false}));
//methodoverrideの引値を設定
app.use(methodOverride('_method'))

//ルーティング
app.get('/',post.index);
app.get('/posts/:id([0-9]+)',post.show);
app.get('/posts/new',post.new);
app.post('/posts/create',parseForm, csrfProtection,post.create);
app.get('/posts/:id/edit',csrfProtection, post.edit);
app.put('/posts/:id/',post.update);
app.delete('/posts/:id/',post.destroy);


app.listen(3000, () => {
  console.log('server is up on port 3000')
});


・edit.ejs【編集ページ】

<%- include ('../partials/header'); %>
<h1>Edit</h1>
//クエリ値を指定してHTTPメソッドを上書き
<form method="post" action="/posts/<%= id %>?_method=PUT">
<input type="text" name="title" value="<%= post.title %>">
<input type="text" name="body" value="<%= post.body %>">
<input type="hidden" name="id" value="<%= id %>">

<input type="submit" value="Update!">
</form>

<p><a href="/">Back to Top</a></p>
<%- include ('../partials/footer'); %>

・index.ejs【記事タイトル一覧&編集・削除ボタン】

<%- include ('../partials/header'); %>
<h1>Posts</h1>
<ul>
<% for (var i=0; i<posts.length; i++){ %>
<li>
    <a href="/posts/<%= i %>"><%= posts[i].title %></a>
    <a href="/posts/<%= i %>/edit">[Edit]</a>
//クエリ値を指定してHTTPメソッドを上書き
    <form method="post" action="/posts/<%= i %>?_method=DELETE">
        <input type="hidden" name="id" value="<%= i %>">
        <input type="submit" value="削除">
    </form>
</li>
<% } %>
</ul>
<p><a href="/posts/new">Add new</a></p>
<%- include ('../partials/footer'); %>
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1