##やりたかったこと##
ユーザが画像を投稿する際に、投稿確認画面で内容確認後、画像投稿を完了させる。
##実行環境##
ruby 3.0.1
Rails 6.0.4.1
使用gem:
carrierwave
pry-rails (デバッグで使用のため)
##問題##
①確認画面(confirm view)から投稿ボタン(form_submit)を押すと、バリデーションエラーが発生する
②モデルに設定したバリデーションを解除し、再投稿したらNil location provided. Can’t build URI.が発生する
##問題の発生理由##
new viewからconfirm viewにページが移る際に画像のデータが渡されずに消えてしまう。
①は確認画面に移る際にユーザーから渡された画像データがロストしてるため、画像データを挿入したフォームデータはNilとなり、モデルに設定したバリデーションに基づいてバリデーションエラーとなった。
②は画像データの入る(※)カラムはNilの状態でsaveされたため、実際の画像データがあるURLを取得出来なかった。
※ 実際にDBに登録されてるのは画像データそのものではなく、画像データの場所を記したURLが格納されている。
##解決手段##
Carrierwaveのキャッシュ機能(※)を使用する
※キャッシュ機能とは、"public/uploads/"フォルダ内にアップロードされたファイルを"public/uploads/tmp/"へコピーして再利用出来るようにする仕組みです。
Carrierwaveのキャッシュ機能を使うためには以下の2点を行う必要があります。
1.Viewに「form.hidden_field :<カラム名>_cache」を追記する。
※form.hidden_fieldとは、View上に入力フォームを生成せずに受け取った値を保持するためのフィールド
# 例)confirm.html.erb
# 省略
<%= form.hidden_field :image_cache %>
# 省略
2.上記1のhidden_fieldで値を保持したデータを受け取るために、ControllerのStrong Parametersに "<カラム名>_cache" を追記する。
実際のモデルやテーブルはキャッシュを格納する属性やカラムを持っていないため、イメージしづらいので注意。
# 例) controller
private
def picture_params
params.require(:picture).permit(:image, :text, :image_cache)
end
##補足という名のメモ##
問題②が発生してしまった場合は対象レコードを削除しないと、対象レコードの情報をViewで表示する際に毎度エラーが発生してしまうため、レコードを削除する必要があります。
# 例)
Picture.all
#=> 結果省略
@picture = Picture.find(x) #.all等で確認した際にimage等のカラムがnilになっていたIDを指定する
@picture.destroy
検証のためにモデルのバリデーションを解除している場合は元に戻す
久しぶりにガッツリ沼ってしまったので、解決出来てよかった~
##参考文献##
carrierwave github
[Rails6]CarrierWaveを基本に忠実に使ってみる~キャッシュ・S3編~
【Rails】CarrierwaveのCache機能を使用し、バリデーション後の画像データを保持する方法
Railsガイド 4.5 Strong Parameters