niki12260714の日記

フリーランスのITエンジニアの呟き。

Ruby学習16日目:画像アップロードと画像表示

やりたいことを整理すると、

・アイテムの商品画像をアップロード。
→場所は/public/imgの下。この時に画像のファイル名を【ユーザーID + アップロード日時】に変更
→アップロードできるのは拡張子が「.jpg」「.gif」「.png」のみ、容量は1M以下
→DBに保存するのは、変更されたファイル名

・アイテム一覧を表示時に、アップロードされた画像を表示する
→DBから値を取得するのは、自分が登録したアイテム情報のみ
→画像パスのカラムには画像名しかないので、View表示時には正しい画像パスに直す

これを一つずつ分解してきます。
まずは、画像のアップロード。

 
<label>アイテム画像:
<%= file_field_tag :upfile, size: 50 %>
</label>

※_form.html.erbのコード、これで以下のようになる

f:id:niki12260714:20170923192057j:plain

View側はこれで終わり、次にアップロードしたファイルを受け取るControllerを修正。

f:id:niki12260714:20170923192300j:plain

privateメソッドに追加したのは2つ、img_processとdelete_img。
まずはimg_processですが、やることは「アップロードしたファイルが形式として正しいのか?」をチェックしています。<チェック条件は上参照
引数でフォルダに保存する画像名を受けているので、チェックを通り抜けられたら引数のファイル名で画像保存します。
そして最後に、全てOKならsuccessという文字、エラーならばエラーメッセージを戻します。

delete_imgは引数でファイル名を貰い、そのファイルを削除するもの。

で、これらを呼ぶのがViewで登録ボタンを押下したときに呼ばれるメソッドです。

f:id:niki12260714:20170923192808j:plain

コメント書きまくっているので、やっているのはコメントの通り。
で、これをみて分かる通り、65,66行目と69,70行目が同じ処理をやっているのにここにべた書きしているのが変……。
いや、分かります、多分こういう書き方しない。
エラーになったときにViewを再描画するのはどこかにまとめておくべきか。
そもそも、このアップロードの検証はmodelに任せるべきではないか?
そうすれば、@item.saveが走った時点でvalidateでエラーになって69,70行目がいらなくなるはず……。
ただ、色々見たんですが、上手くmodelにViewから渡ってきたファイルデータが行っていないようで、検証時にnilになっちゃうんですよね。
なので、ここは暫定処理。

さて次は、アイテムの一覧を表示するときに、アイテム画像のカラムにはファイル名ではなく画像を表示させます。
まずはControllerで、取得してくるアイテムを「アイテム登録したユーザ(つまりはログインユーザー)」のみにします。

f:id:niki12260714:20170923193706j:plain

そして取ってきた値に対し、画像はパスを付けてあげないといけません。
なので、modelにコールバック関数、after_findを定義します。

# コールバック関数
after_find :create_img_path

 create_img_pathはどんなかというと、こんな感じ。

f:id:niki12260714:20170923194052j:plain

調べたところによると、

・after_findはApplicationRecordが生成されるたびに呼び出されるので、件数が増えると処理が重くなる
・画像やcssjavascriptといったファイルの置き場所には、アセットパイプラインというものが通され、フレームワークはアセットパイプラインが通っているところから画像などをとってくる
→説明難しい……通常、Ruby on railsでは画像とかcss,javascriptはassetsというフォルダの中に格納しておいて、サーバーに展開したときにフレームワークがその中にある画像とかとってくる。
→assetsに対してはデフォルトでアセットパイプラインが通っているが、その他のフォルダに外部ファイルを置きたいというのであれば、アセットパイプラインを通さなければいけない
→publicにもアセットパイプラインが通っている模様。なので、Viewから画像を呼び出すのであれば、publicからのパスを渡せばいい
→逆にControllerとかmodelから見るときはpublicからパスを指定しないといけない

こういう解釈でいいのかな、動きをみるとこういう感じっぽい。

さて、これをViewに展開させると、こうなります。

f:id:niki12260714:20170923194918j:plain

※index.html.erb

書き換えたのは29行目、ここをimage_tagにし、modelで編集した画像パスが渡されます。
これで実際に画像表示できます。

f:id:niki12260714:20170923195222j:plain

見た目があれなのは、今は気にしないで!
まずは目標はクリアしました。
次は取り置き依頼を受け付ける画面と、そこで受け付けたユーザを一覧表示する画面の作成です。