web-dev-qa-db-ja.com

jQuery ajaxリクエストがRails controller?

HTML、JS、JSONリクエストに応答するように設定された標準コントローラーがあります。

def picture
  @picture = Picture.new params[:picture]

  respond_to do |format|
    if @picture.save
      format.html do
        logger.debug "In the HTML responder"
        redirect_to @picture
      end
      format.json { render json: @picture, status: :created, location: @picture }
      format.js { render :nothing => true }
    else
      # you get the idea
    end
  end
end

現在、$.ajax関数を使用してそのコントローラーにリクエストを送信しようとしています(この特定の状況では:remote => trueを使用できません-Ajaxファイルのアップロードを機能させようとしています)。

$.ajax({
  url: $("form#new_picture").attr("action"),
  type: "POST",
  data: formdata,
  processData: false,
  contentType: false
});

問題は、私のリクエストが何らかの理由でHTMLリクエストとして扱われていることです。 Rails JS応答が必要であることをどのように伝えますか?

ちなみに、私はプロジェクトでjquery_ujsを使用しているので、必要に応じて、jquery_ujsが提供するメソッドにアクセスできます。ここで必要なことを行うには、JSを調整するのに十分なJSはありません。

35
David Tuite

このソリューションは私にはうまくいきませんでした(Rails 3.1 + coffeescript)。たくさん検索した後、私はそれを行う良い方法を見つけ、共有したいと思いました。

URLの最後に「.js」を追加するだけです。とても簡単... ​​;-)

53
ndemoreau

dataType: 'script'を追加するだけです

$.ajax({
  url: $("form#new_picture").attr("action"),
  type: "POST",
  data: formdata,
  processData: false,
  contentType: false,
  dataType: 'script'
});    
32
shlensky

Railsが応答方法を認識できるように、ajaxリクエストを送信する前に 'accept'ヘッダーを設定する必要があります。

$.ajax({
  url: $("form#new_picture").attr("action"),
  type: "POST",
  data: formdata,
  processData: false,
  contentType: false,
  beforeSend: function(xhr, settings) {
    xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
  }
});
7
David Tuite

dataType: 'script'を追加し、フォームのデータに次のようにパラメーターformat: 'js'を追加します。

$.ajax({
  url: '/manager/consumers/url',
  type: 'GET',
  dataType: 'script',
  data: {
  authenticity_token: '<%= form_authenticity_token %>',
  param_1: '1',
  param_2: '2',
  format: 'js'
  }
});

また、レイアウトをレンダリングしないようにコントローラーを追加します。

  respond_to do |format|
      format.xls 
      format.js { render :layout => false }
    end
5
overallduka

ここで何が起こっているのかを説明しましょう。

クライアントがサーバーに送信するAcceptヘッダーとContent-typeヘッダーがHTTPで混乱していることがよくあります。 Acceptヘッダーは、サーバーにどのコンテンツタイプ(application/json、application/javascript、application/octet-stream、audio/mpeg、image/png、multipart/alternative、text/plain、text/html、text/csv)を通知するために使用されます、video/mpegなど)を受け入れます。サーバーは、コンテンツの実際のコンテンツタイプをクライアントに通知するContent-Typeヘッダーを含む応答を返します。

HTTPリクエストはContent-Typeも指定できます。フォームデータにはすべてのタイプのデータが含まれる可能性があり、Content-Typeヘッダーはデータを実際に何であるかをサーバーに通知できるためです(例:multipart/form-data)。 multipart/form-dataのようなさまざまなメディアタイプはMIMEとして知られています。

JQuery.ajax()には、このトピックに関連して渡すことができる別のパラメーターがあります。accepts、contentType、dataTypeです。

Content-Type HTTPヘッダーを理解していれば、contentType属性は明確です。これは、データが実際に何であるかをサーバーに伝えます。 jQueryのデフォルトは「application/x-www-form-urlencoded; charset = UTF-8」で、ほとんどの場合これで問題ありません。

Acceptヘッダーは、サーバーがどのContent-Typeを受け入れるかを通知することに注意してください。しかし、jQueryのドキュメントのdataTypeを読むと、「サーバーから返されると予想されるデータのタイプ」とよく似ています。違いは何ですか?

Accepts属性を使用すると、リクエストのAcceptヘッダーを変更できます。ただし、dataTypeを変更するとAcceptヘッダーも変更されるため、accept属性を変更する必要はありません。 dataTypeはAcceptヘッダーを変更します。 dataTypeの利点は、成功ハンドラで使用できるようになる前に応答を前処理できることです。

実際には、Rails何を応答ヘッダーとして受け入れるかを伝える必要があるため、dataTypeを変更します。Railsシンボル:jsおよび:jsonたとえば、HTTP MIMEタイプに対応します。

Mime::Type.register "text/javascript", :js, %w( application/javascript application/x-javascript )
Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )

したがって、respond_toブロックで:jsオプションをトリガーする場合は、jQueryでスクリプトとしてdataTypeを指定する必要があります。そして、答えの1つが示すように、次のようにします。

$.ajax({
  url: "users/populate_user,
  type: "POST",
  data: formdata,
  dataType: 'script'
});  

リクエストヘッダーがどのように美しいか見てみましょう。

enter image description here

DataTypeをスクリプトとして指定すると、Acceptヘッダーがapplication/javascriptにどのように変更されたかに注意してください。また、contentTypeが「application/x-www-form-urlencoded; charset = UTF-8」であることに注意してください。これが何も指定されていない場合にjQueryが使用するデフォルトのContent-Typeだと言ったことを覚えていますか?このSO=ページで提供されている別の回答もこのオプションを指定しています:

  contentType: false

JQueryのドキュメントによると:

JQuery 1.6以降では、falseを渡してjQueryにコンテンツタイプヘッダーを設定しないように指示できます。

最後のポイントです。 Railsコントローラーでは、このコントローラーアクションが:jsに応答するだけの場合は、:jsフラグを指定する必要はありません。respond_toをコントローラーから省略するだけです。

  def populate_user
    @user = User.from_names(params[:name][:value]).first
  end

そして、users/populate_user.js.erbファイルを追加します。また、ルートが投稿リクエスト用に設定されていることを確認してください:

post 'users/populate_user', to: 'users#populate_user'

SOから回答をコピーして貼り付ける場合、プロジェクトで何を使用しているかを正確に理解することも重要です。

3
Donato

これがxhrリクエストであるかどうかを確認し、希望する形式をレンダリングできます。例えば;

if request.xhr?
  render :json => {
    :some_data => 'bla'
  }
end
3
user3375663

質問に直接答えることはできないかもしれませんが、私はこれに似た問題を見つけました。特にhamlを使用する場合。

多くの試行(URLへの.jsの追加を含む)の後、私のために機能したのは、スクリプト応答を返すときにレイアウトレンダラーを無効にすることだけでした。

  respond_to do |format|
    format.html
    format.js { render layout: false }
  end

私の問題は、AJAX応答がRailsレイアウトテンプレートメカニズムによって生成された完全なHTMLページであったことです。これは、私のJavaScriptがthing.js.erbは実行されていませんでした。レイアウトを無効にすると、JavaScriptのみが返され(開発者ペインのブラウザーのネットワークタブに戻ります)、実行が許可されました。

私はデフォルトのレンダラーとしてhamlを使用しています。それが、jsレンダーでレイアウトを明示的に無効にする必要がある理由だと思います(自動であると想定していました)。

したがって、他に何も機能せず、hamlを使用する場合は、これを試してください。

3
92tonywills

contentType"text/javascript"として設定します

$.ajax({
  url: $("form#new_picture").attr("action"),
  type: "POST",
  data: formdata,
  processData: false,
  contentType: "text/javascript"
});   
0
shweta