7/29~ プチ断食日記をスタート! 毎日更新中!

[ Rails ] Ajaxで画像アップロードする際、406 Not Acceptableでハマった話 [ CarrierWave ]

rails-logo

 

こんにちは。たなかです。

普段はRailsでWebアプリ開発をさせてもらっています。

 

FatFreeCRMっていう顧客管理システム用のgemを扱っているのですが、こちらにAWS S3への画像アップロード機能を持たせたいということで実装していたところ、以下のような症状に陥ったので備忘録的にシェアしておきます。

症状

画像を追加し、リソースの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を求めているようです。なんでじゃろ???

解決方法

先に結論

Railsのgem、『Remotipart』を導入する!

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によるファイルアップロードが可能になりました。よかった〜〜!

まとめ

 

いや〜めちゃハマりました。

S3に画像のアップロード自体はできてたので、「アップロードの行き場に迷ってるんだろうな〜」ってのは割とすぐわかったのですが、「remote: tureではファイルアップロードできない」っていうことに気づくのに時間がかかってしまった〜〜〜。

結局技術者に相談して本件は解消できました。精進が必要ですな……。

 

ちなみにCarrierWave先生も「非同期でアップロードするならremotipartが簡単」って仰ってました。
「非同期でファイルアップロードできないなー」とお悩みの方はご参考までに。

参考サイト

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です