こんにちは。たなか(@tanaka_ricecake)です。
普段はRailsでWebアプリ開発をさせてもらっています。
FatFreeCRMっていう顧客管理システム用のgemを扱っているのですが、こちらにAWS S3への画像アップロード機能を持たせたいということで実装していたところ、406 Not Acceptable
という以下のようなエラー症状にハマりました。
今回は解決までの方法を備忘録的にシェアしておきます。
もくじ
Completed 406 Not Acceptable
画像を追加し、リソースのcreateを行うと以下のエラー。
Completed 406 Not Acceptable in 6081ms (ActiveRecord: 30.2ms)
ActionController::UnknownFormat (ActionController::UnknownFormat):
app/controllers/entities/accounts_controller.rb:61:in `create'
フォーマットがなくて怒っているよう。
今回はよくあるcarrierwave + fogでS3にファイルアップロードを行う手順を踏んでます。
上記の処理はAjax(非同期)を用いて実装しているため、accountを作成したら「画面遷移を挟まず、一覧画面に新しいアカウントが追加される」という動きになってほしい……。
なので、こちらとしてはcreate.js.hamlに飛んでいってほしいところですが、create.html.hamlを求めているようです。なんでじゃろ???
Completed 406 Not Acceptable 解決方法
Railsのgem、『Remotipart』を導入する!
先に結論から書くとRemotipartを導入することで解決できました。
『Remotipart』Githubページはこちら
RemotipartのGithubページを見れば一通り書いてありますが、ざっくりとこちらでも導入方法を記載しておきます。
まずはGemfileにremotipartを追加。
gem 'remotipart'
bundle installを走らせたら、javascripts/application.jsに以下を追加。
//= require jquery.remotipart
あとは通常通り、アップロードを行うフォームにてremote: tureを追記してやるのみです。
ここまでで、画像つきのaccountをAjaxで作成することに成功しました。とりあえず一安心。
つまりどういうことだってばよ?
「remote: true」がキーポイント
Railsの機能で、リンクやフォームなどを簡単に非同期化(Ajax)できるremote: trueってのがあります。
link_toやform_forなどにオプションとして設定することで利用可能。これによって、リクエストがhtml形式ではなく、js形式になります。
通常link_toやform_forはhtml形式のリクエストになりますが、リクエストがjs形式になると探しにいくファイルが、html.erbではなくjs.erbに変わります。
なのでremote: trueを設定すると、html.erbをレンダリングしないためページ遷移が発生しません。変わりにjs.erbに記述したJavascriptが実行されます。
ファイルのアップロード
remote: trueはファイルのアップロードに対応してくれていません。
multipartなフォーム(textやfileなど混在しているようなフォーム)でremote: trueを設定しても非同期送信してくれないようです。
それを解消してくれるのが先にあげたgem、’remotipart’でした。
内部的に何をやっているか具体的なところまでは紐解けていませんが、導入してオプション追加するだけでAjaxによるファイルアップロードが可能になりました。よかった〜〜!
Completed 406 Not Acceptable まとめ
ということで今回はRailsの406 Not AcceptableエラーでAjax画像アップロードができない問題についてご紹介しました。
いや〜めちゃハマりました。
S3に画像のアップロード自体はできてたので、「アップロードの行き場に迷ってるんだろうな〜」ってのは割とすぐわかったのですが、「remote: tureではファイルアップロードできない」っていうことに気づくのに時間がかかってしまった〜〜〜。
結局技術者に相談して本件は解消できました。精進が必要ですな……。