はじめに
<input type="file">
で画像を送信・保存したときのCarrierWaveの動作(public/upload
配下に画像を保存、カラムには画像名を保存)と同じような動作を、非同期でやりたかった。
こちらが実際に練習で作成してみたアプリ https://drawemapp.herokuapp.com/
開発環境rails
:6.0.4.4ruby
:2.7.5carrierwave
:2.2.2
実装の流れ
canvas
に記載されている画像からblob
オブジェクトを生成FormData
オブジェクトにblob
を挿入blob
を挿入したFormData
を非同期で送信- コントローラーでデータを受け取り、
DB
に保存する
HTML・CSS
はじめにcanvas
を作成します。
<canvas class="drawPicture" id="js-drawPicture" width="600" height="400"></canvas>
<button id= "js-pictureUpload">アップロード</button>
.drawPicture {
background-color: white;
border:3px solid;
}
JavaScript
fetchAPI
を使用して、データを非同期で送信しています。
let canvas = document.getElementById('js-drawPicture');
let ctx = canvas.getContext('2d');
const pictureUpload = document.getElementById('js-pictureUpload');
// クリックしたら発火
pictureUpload.addEventListener('click', async ()=> {
// blobオブジェクトの作成
let imageBlob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
// FormDateオブジェクトの作成
let formData = new FormData();
// <input type="file"> のようにフィールドを追加
// 第一引数はparamsで受け取るための名前になります。post[picture]とすることでストロングパラメータを使用して、受け取れます。
formData.append("post[picture]", imageBlob, "picture.png");
// CSRF対策
const token = document.getElementsByName("csrf-token")[0].content;
// データを送信
let response = await fetch('/posts', {
method: 'POST',
headers: {'X-CSRF-Token': token},
body: formData
});
// 送信後、一覧画面に移動します。
let location = window.location.replace('/posts')
};
toBlob(callback, type, encoderOptions)メソッド
は画像データに対応するblob
オブジェクトを生成し, 処理を行います。
promise
、async
、await
を使用すれば、blob
オブジェクトを簡単に変数に代入できます。
// callbackに処理をまとめたバージョン
// これでも動作します
canvas.toBlob((blob)=> {
let imageBlob = blob;
let formData = new FormData();
formData.append("post[picture]", imageBlob, "picture.png");
const token = document.getElementsByName("csrf-token")[0].content;
let response = fetch('/posts', {
method: 'POST',
headers: {'X-CSRF-Token': token},
body: formData
});
let location = window.location.replace('/posts')
}, 'image/png');
Promise
、async
、await
、fetch
などの解説をすると長くなってしまうので、省略します。下記のサイトを参考にしてください。

Promise
Controller
class PostsController < ApplicationController
def new; end
def index
@posts = Post.all
end
# blobを受け取り、DBに保存
def create
@post = Post.new(post_params)
@post.save
end
private
// ストロングパラメーター
def post_params
params.require(:post).permit(:picture)
end
end
まとめ
正常に保存されていたら、public/upload
配下に画像が保存され、DBには画像名が保存されているはずです。
保存した画像は、carrierwave
のurl
メソッドで呼び出せます。
間違いがあったら、コメントしていただけると嬉しいです。
コメント