はじめに
この記事はソニックガーデン 若手プログラマ Advent Calendar 2024 の20日目の記事です。
今回のアドベントカレンダーでは2回目の投稿です!💪(1回目の記事)
今回はRailsを使ってダイレクトアップロード機能を実装したのですが、コントローラが受け取るフォームのパラメーターの順番が原因で少しハマったのでご紹介。
開発環境
- Ruby 3.3.6
- Rails 8.0.0
実装
ダイレクトアップロード機能の実装
Railsガイドを参考にしながら、実装しました。
どういう問題が起きるか予想しながら読んでみると面白いかもです。
= simple_form_for [:admin, book] do |f|
= f.input :front_cover, input_html: { direct_upload: true }
= f.input :front_cover, as: :hidden, input_html: { value: book.front_cover.signed_id } if book.front_cover.attached?
= image_tag book.front_cover.variant(:thumbnail), class: 'mb-5' if book.front_cover.attached?
= f.button :submit
※まんまscaffoldです。
class Admin::BooksController < Admin::ApplicationController
before_action :set_book, only: %i[show edit update]
def new
@book = Book.new
end
def create
@book = Book.new(book_params)
if @book.save
redirect_to admin_book_path(@book), notice: t('controller.created')
else
render :new, status: :unprocessable_entity
end
end
def show
end
def edit
end
def update
if @book.update(book_params)
redirect_to admin_book_path(@book), notice: t('controller.updated'), status: :see_other
else
render :edit, status: :unprocessable_entity
end
end
private
def set_book
@book = Book.find(params.expect(:id))
end
def book_params
params.expect(book: %i[ front_cover ])
end
end
起きたこと
編集フォームで表紙画像の更新ができませんでした。
調査
updateアクションの中でparams[:book][:front_cover]
が既に紐づいているbookのfront_coverのsigned_idと同じ値でした。(signed_idをご存知ない方は、こちらの記事をご覧いただくと分かり易いかと思います。)
新しいファイルを添付して送信してるはずなのに、なぜ前回の画像のsigned_idと同じなのか。
そういえばフォームのfront_coverパラメータが1つだけど、もしかしてhiddenパラメータの行が優先されているのでは?と思い、試しにフィールドを逆にしてみたところ、ちゃんと画像が更新されるようになりました✨
- = f.input :front_cover, input_html: { direct_upload: true }
- = f.input :front_cover, as: :hidden, input_html: { value: book.front_cover.signed_id } if book.front_cover.attached?
+ = f.input :front_cover, as: :hidden, input_html: { value: book.front_cover.signed_id } if book.front_cover.attached?
+ = f.input :front_cover, input_html: { direct_upload: true }
パラメータが重複していた場合、後ろの値が上書きするみたいですね。
一応コンソールで確認してみました。
ActionController::Parameters.new({
book:
{ name: 'aaa',
name: 'bbb'
}
}
)
(cherry-online):48: warning: key :name is duplicated and overwritten on line 49
=> #<ActionController::Parameters {"book"=>{"name"=>"bbb"}} permitted: false>
>>
aaaではなく、後ろに存在するbbbの値で上書きしていますね。
実はActive Storageのサンプルコードには、ちゃんと新しくアップロードする画像のフィールドをhiddenパラメータの下に書いてありました。。。
お恥ずかしい。なんのためのサンプルコードやねん。
最後に
今までパラメータが重複するということがなかったので、いい学びになりました。
最後まで読んでいただき、ありがとうございました〜!
明日は @samayou さんが執筆予定です。お楽しみに〜!