テックキャンプ112日目〜複数枚画像投稿機能①

kobasaです(´ω`*)
プレビューが終わったので複数枚の画像を投稿できるようにします。
まずはプレビューで使用したミニアプリを使用して実装します。

112日目の勉強内容

サーバーサイドの実装

アソシエーションの設定

複数の画像を投稿するためにアソシエーションの記述を変更する。

has_many_attached :images

has_many_attachedメソッドは投稿と画像の間に1対多の関係性を表す。

フォームとストロングパラメータを複数枚対応にする

フォームの画像投稿部分を複数枚投稿に対応できるように編集する。

<%= f.file_field :images, name: 'message[images][]', id: 'message_image' %>

カラム名にあたる部分をimagesに変更し、nameオプションを設定。
オプションの設定がないとname=’message[image]’になってしまい複数投稿に対応できない。
[]は配列の意味でこの中に複数の画像が格納される。と思う。

次にストロングパラメータを複数枚投稿に対応できるように編集する。

params.require(:message).permit(:content, images: [])

中間テーブルで使用した○○_ids: []とは意味が異なる。はず。(中間テーブル理解できてない)
今回は画像を配列で受け取れるようにしているだけ。

最後にビューを複数枚表示できるような記述にする。
プレビューの編集時に使用した「画像が保存されていれば表示」の条件式は削除。

JavaScriptの編集

複数投稿にするので既に画像がブラウザ上にあれば削除する処理は不要。

HTML生成時にファイル選択ボタンも生成するようにする。

const inputHTML = document.createElement('input');
inputHTML.setAttribute('id', 'message_image_${imageElementNum}');
inputHTML.setAttribute('name', 'message[images][]');
inputHTML.setAttribute('type', 'file');
# 上記の記述で作成されるinput要素
<input id="message_image_(番号)" name="message[images][]" type="file">

変数imageElementNumは後で記述するがlengthを使用して番号を格納する。
これによりidに番号が割り振られ、「何番目の画像か」の判別が可能になる。


const imageElement = document.createElement('div');
imageElement.setAttribute('class', 'image-element');
let imageElementNum = document.querySelectorAll('.image-element').length;

1行目のdivの生成はプレビュー時に記述したもの。生成したdivにクラスを付与する。
ブラウザ上にある付与したクラスの数を変数に格納する。


imageElement.appendChild(inputHTML);

生成したinput要素を生成したdiv要素の中に表示させる記述。
これで画像の後にinput要素が表示される。


次に生成したinput要素で画像を選択すると2枚目以降のプレビューが表示されるようにする。

inputHTML.addEventListener('change', (e) => {
  file = e.target.files[0];
  blob = window.URL.createObjectURL(file);

createImageHTML(blob);
});

プレビュー表示の記述とほとんど同じだが、イベント発火対象が生成したinput要素になっている。
これで生成したinput要素で画像を選択すると再び画像を表示する関数が働く。
2枚目に選択した画像を取得する記述が1枚目と同じだけど、問題なく動く。
添字が0だから新しく選択したファイルが0番目にくる挙動なんだろうか?

フリマ実装に向けて

カリキュラムではここで終わりなんですよね。足りていなさそうな機能は、
・投稿/編集時の画像選択し直し・取り消し。
・投稿枚数の制限。

考えないといけないことは、
・プレビュー表示の仕方(CSS)
・一覧画面・購入画面での表示(最初に選択した画像のみを表示する?)
・詳細画面での表示(詳細画面には全ての画像を表示。SoldOut表示の兼ね合いもある)
 全ての画像を小さく表示しておき、選択した画像のみが大きい画面に表示される。
 みたいなことをしたい(Amazonみたいな感じ)

めっちゃ時間かかりそう(´・ω・`)
とりあえずカリキュラムの部分まで実装して後で考えようかw

コメント

  1. AR練習おじさん より:

    僕も最後の3点めっちゃ悩みました。
    特に最後の拡大表示は諦めましたね。jquery入れたらできそうと思ったんですけど導入の仕方がわからず挫折中ですw

タイトルとURLをコピーしました