11
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ソニックガーデン 若手プログラマAdvent Calendar 2024

Day 20

Railsでコントローラに渡すパラメータの順番を意識しようと思った話

Last updated at Posted at 2024-12-20

はじめに

この記事はソニックガーデン 若手プログラマ Advent Calendar 2024 の20日目の記事です。
今回のアドベントカレンダーでは2回目の投稿です!💪(1回目の記事)

今回はRailsを使ってダイレクトアップロード機能を実装したのですが、コントローラが受け取るフォームのパラメーターの順番が原因で少しハマったのでご紹介。

開発環境

  • Ruby 3.3.6
  • Rails 8.0.0

実装

ダイレクトアップロード機能の実装

Railsガイドを参考にしながら、実装しました。
どういう問題が起きるか予想しながら読んでみると面白いかもです。

app/views/admin/books/_form.html.haml
= 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です。

app/controllers/admin/books_controller.rb
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パラメータの行が優先されているのでは?と思い、試しにフィールドを逆にしてみたところ、ちゃんと画像が更新されるようになりました✨

haml
-  = 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 さんが執筆予定です。お楽しみに〜!

11
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?