2023年11月現在、Cloudinaryのページのデザインが、「Next.jsでつくるフルスタックアプリ(2022年4月発売、TypeScript版は2022年9月)」および「MERNでつくるフルスタックアプリ(2022年10月発売)」執筆時から変更されています。
第10章の「画像のアップロード」で紹介しているCloudinaryサイト上での設定は、下の記述で読み替えて進めてください。
すでに気が付いた人がいると思いますが、前章まで開発したアプリの画像はすべてpublic
フォルダに入ったものが使われています。そのため、ユーザーが好きな画像を使いたい場合のニーズには対応できていません。この点を修正していきます。
まず画像を保存する場所がどこか考えましょう。普通に考えると、現在MongoDBというデータベースがあるのだから、そこを使うと思うのが普通です。しかし多くのアプリで、画像自体をデータベースに保存するのではなく、画像のパス(URL)を保存するという方法がとられます。これは画像の容量が大きいからです。そして画像は、他の画像保存に適したサービス、特にAmazonのAWSやCloudinaryなどに保存する方法が取られます。
それでは画像をMongoDBに保存することは不可能なのでしょうか。実は画像をBase64などの方法で文字列へと変換して保存することは可能です。こちらのサービス(https://www.base64-image.de)などでは、画像をBase64で文字列へと変換できます。しかし、これは文字列といってもとても量が多く容量の重い文字列となるため、MongoDBに実際に保存してみるとわかりますが、MongoDBの動きが非常に遅くなり、バックエンドの読み取り時に頻繁にエラーが発生するようになります。なので本書ではこれ以降、無料のCloudinaryを使った画像保存の方法を紹介していきます。
まずユーザー登録をします。次のURLにアクセスして、右の「SIGN UP FOR FREE」をクリックします。
Googleアカウントなどでも登録はできますが、ここではメールアドレスを使いたいので「SIGN UP WITH EMAIL」を選びましょう。
名前、メールアドレス、パスワードを入力します。「I'm not a robot」にチェックを入れて、「GET STARTED NOW」を押します。認証メールを送信した通知が出るので、メールの受信フォルダを確認してメールアドレスの認証を済ませます。
認証メールをクリックすると、ダッシュボード画面に移ります。ここで表示されている下図の赤丸「cloud_name」は後ほど必要なので、どこかにコピーしておいてください。
左のメニューバーの下部にある歯車のアイコンをクリックします。
画像アップロードの設定をするので「Upload」をクリックします。
下にスクロールして「Enable unsigned uploading」をクリックし、サインインしていないユーザーでも画像をアップロードできるようにします。
クリックすると「Unsigned」の項目が追加されるので、次はその下の「Add upload preset」をクリックします。
「Signing Mode」を「Unsigned」に変えます。ここで下図赤枠の「Upload preset name」をどこかにコピーしておいてください。なおこの「Upload preset name」は自分の好きなものに変えられますが、ここではこのデフォルトのもので進めます。最後に上部の「Save」ボタンを押しましょう。
以上でCloudinaryの設定は終了です。次はここに画像をアップロードするためのコードを追加します。
コードを追加する場所はバックエンド、フロントエンド両方可能ですが、今回バックエンドに追加をすると様々な部分のコード変更が必要になるため、ここでは一番簡単に済むフロントエンド側に画像アップロードの機能を追加します。
最初に画像アップロード機能を持つコンポーネントを作りましょう。imgInput.js
をcomponents
フォルダに追加します。
そこに次のコードを追加します。ここで使われているのはtry catch
、await
など本書で何度も出てきたコードです。try
文の中がCloudinaryへとアップロードするための専用のコードになっています。
なお各自のアカウント情報に応じて直してもらいたいのは、下の3ヶ所です。
data.append("upload_preset", "uwjjedr")
// ↑先ほどコピーした「Upload preset name」に変更してください。
data.append("cloud_name", "efo323cm")
// ↑先ほどコピーした「Cloud name」に変更してください。ここでは"efo323cm"となっています。
const response= await fetch("https://api.cloudinary.com/v1_1/efo323cm/image/upload"
// ↑"v1_1/"以降を登録画面で設定した「Cloud name」に変更してください。ここでは"efo323cm"となっています。
// imgInput.js
import { useState } from "react"
const ImgInput = (props) => {
const [imageFile, setImageFile ] = useState("")
const handleClick = async() => {
try{
const data = new FormData()
data.append("file", imageFile)
data.append("upload_preset", "uwjjedr")
data.append("cloud_name","efo323cm")
const response= await fetch("https://api.cloudinary.com/v1_1/efo323cm/image/upload", {method: "POST", body: data})
const jsonData = await response.json()
await props.setImage(jsonData.url)
alert("画像アップロード成功")
}catch(err){
alert("画像アップロード失敗")
}
}
return (
<div className="img-input">
<input type="file" onChange= {(e)=> setImageFile(e.target.files[0])} accept="image/png, image/jpg"/>
<button onClick={handleClick} disabled={!imageFile}>画像Upload</button>
</div>
)
}
export default ImgInput
(*変更点の解説は以上です。続きは書籍を参考にしてください。)