デフォルトではajaxでファイル送信はできないのですが、それを可能にするのが、remotipartというgemです。
ただ単にファイル送信を可能にするだけならgemをインストールするだけで終わりなのですが、レスポンスを受け取ってエラーを表示したいときに少しはまったので解決策を書いておきます。
remotipartのインストール
railsアプリ内で使うことを前提としています。
まず、Gemfileに追加&bundle install します
# ajaxでファイル送信を行うのに必要 gem 'remotipart'
bundle installが終わると、jquery.remotipart.jsというjsもインストールされるので、 vendor/assets/javascripts あたりに置いておきます。
ファイル送信を行う画面が読み込んでいるjsファイル内で、
//= require jquery.remotipart
と書いておきます。
以上でインストールは終わりです。
remotipartを使ったときの不思議な挙動
1. xhr.responseJSONが取れない
$("form").on('ajax:error', function(event, xhr, status, error) { console.log(xhr.responseJSON); }
とすれば、エラーメッセージが配列で表示されるはず(バリデーションエラーなどでは、そのようなjsonを返している)なのですが、なぜか、ファイルを送った場合だけjsonがxhr.responseJSONが取れなかったです。
解決策
form_forのオプションに data: {type: :json}を追加することで解決できました。
サーバのログを見ていると、ファイルがあるときは、レスポンスフォーマットがjsになっていました。何も指定しないとそうなるようです。
2. ‘ajax:success'が発火しない
上記の解決策をし、サーバー側で以下のような処理をしていると起こります。
def update if @user.update(update_params) respond_to do |format| format.json { head :no_content, status: :ok } end end end
画面側では、
<script type="text/javascript"> $("form") .on('ajax:success', function() { location.reload(); }) .on('ajax:error', function(event, xhr, status, error) { console.log(xhr.responseJSON); }); </script>
としていました。
ですが、ファイルを送信した場合だけ、なぜか'ajax:success'が発火しないです。ファイルを選択しない場合は問題なく動作しました。
解決策
問題はhead no_contentの部分です。
ここを、
def update if @user.update(update_params) respond_to do |format| format.json { render json: @user, status: :ok } end end end
のように、何か値を送ると、ちゃんと発火するようになりました。