
この記事はRailsでjQueryを使ったAjax通信についてのお話です。
Railsに限らず、Ajax通信を行う際、jQueryのajax関数がよく使われます。今回はどのようにして使うのか紹介していきたいと思います。
目次
jQueryのajax関数
まず、さらっとajax関数についてです。
ajax関数は、受け渡しパラメータの設定を始め、エラー処理、サーバーからのパラメータ受け取りなどマルチな機能を有するjQueryの関数です。
オーソドックスな使い方は以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
$.ajax({ url: "/hoge.com/root/", type: "GET", // WebAPIを指定 data: params // 受け渡しパラメータオブジェクト }) .done(function (data, textStatus, jqXHR) { // サーバー通信成功した場合はこの中の処理が起動 // 引数のdataオブジェクトの中にはRailsから受け取ったパラメータが格納されている }) .fail(function() { // サーバーエラーが起きた場合はこの中の処理が起動 }); // 例↓ // サーバーに受け渡すパラメータをオブジェクト形式で作成 var params = { id: "1", val: "あいうえお" } $.ajax({ url: "/hoge.com/root/getmessage", type: "GET", // WebAPIを指定 data: params // 受け渡しパラメータオブジェクト }) .done(function (data, textStatus, jqXHR) { // サーバー通信成功した場合はこの中の処理が起動 // 引数のdataオブジェクトの中にはRailsから受け取ったパラメータが格納されている var message = data.message ; console.log(message); }) .fail(function() { // サーバーエラーが起きた場合はこの中の処理が起動 console.log("エラーが発生しました。"); }); |
「$.ajax」内では通信先URL、WebAPIのタイプ、サーバー側(Rails)に受け渡すパラメータを設定します。
(他にも設定出来る項目は多数あります)
デフォルトの場合、実行後サーバーから通信結果が返るまでの間、非同期通信となり画面処理が進行します。
(ボタンクリックなどができてしまうので自前で操作ロックをかけておく必要があります。)
「done」内で通信成功後の処理を記述します。
関数の引数に指定している「data」には、通信成功後にサーバーから受け取ったパラメータがオブジェクト形式で格納されているので、done内で受け取る事が出来ます。
(サーバーから受け渡すパラメータについては後述します。)
「fail」内はサーバーエラーが起きた場合の処理を記述します。
この中ではエラーのアラートを表示したり、画面ロックやローディング解除を行います。
「done」「fail」は省略可能ですが、特別理由がない場合は付けておいた方が通信結果が取得できるので便利です。
ajax関数は奥深くここでは書ききれないくらい多くの機能が備わっています。
詳しくはこちらの記事が参考になるので確認してみてください↓
Rails側の設定
jQueryでフロント側の設定が出来たので、今度は通信を受け取るサーバー側(Rails)の準備を行います。
通常のactionと同じようにコントローラに関数を作ります。
1 2 3 4 5 6 |
class Root < ApplicationController def getmessage end end |
ajax関数の「data」に設定したパラメータ変数「params」の値は、paramsというハッシュとして渡ってくるので以下のようにして取得できます。
1 2 3 4 5 6 7 8 |
class Root < ApplicationController def getmessage id = params[:id] # 1 val = params[:val] # あいうえお end end |
受け取ったパラメータを元にDB検索などの処理を行った後、フロントに値を受け渡す必要があります。
Railsでは、Ajax通信の場合、フロントに値を受け渡す方法が2通りあります。
① .js.erbで管理する方法
1つ目は、「~.js.erb」ファイルをViewに作成して管理する方法です。
「localhost:3000/root/getmessage」の処理結果を取得するのであれば「View」ディレクトリの「root」内に新たに「getmessage .js.erb」ファイルを作成します。
このファイルの中身は基本的にjsファイルと同じように記述出来るので、あらかじめ用意しておいたグローバル変数や、HTMLのタグのvalueなどに受け取ったパラメータをセットします。
1 2 3 4 5 |
// 用意しておいたグローバル変数にRailsのインスタンス変数を代入 message = '<%=@message%>'; // タグのvalueなどにも代入出来る $('#hoge-tag').value('<%=@message%>'); |
ちなみに、.js.erbの処理の後、jQueryのajax関数内で「done」を設定している場合、「done」内の処理が走ります。
また、なにも画面側に値を返さない場合にも、中身が空の.js.erbファイルが必要です。
Railsはactionの処理を終えた後、必ず指定されたformatの形式のファイルを返します。
通常通信時は同じaction名のhtml.erbファイル、
Ajax通信の場合は同じaction名のjs.erbファイルを返します。
こちらの記事が分かりやすかったので参照ください↓
Railsで remote: true と js.erbを使って簡単にAjax(非同期通信)を実装しよう!(いいね機能のデモ付)
② ルーティングでactionのformatをJSONに設定する
上記した.js.erbの方法は、actionごとに作成する為.js.erbファイルが膨大な数になり後々管理が大変になると個人的に感じました。
そのため、このもう一つの方法を推奨します。
ルーティングでajax通信を行うactionのformatをJSON形式に設定する方法です。
ajax通信を行うactionのルーティングを以下のように指定します。
1 |
get 'root/getmessage', defaults: {format: 'json'} |
コントローラファイルのaction関数最後の処理に、「render json」でJSON形式のデータをフロントへ返します。
1 2 3 4 5 6 7 8 9 10 11 |
class Root < ApplicationController def getmessage # 処理 # 処理後フロントに渡す値をセットする render json: { :message => "かきくけこ" } end end |
ajaxのdone内の関数の引数「data」にjson形式で指定したデータが格納されます。
1 2 3 4 5 6 7 8 9 10 11 12 |
$.ajax({ url: "/hoge.com/root/getmessage", type: "GET", data: params }) .done(function (data, textStatus, jqXHR) { var message = data.message ; console.log(message); // かきくけこ }) .fail(function() { console.log("エラーが発生しました。"); }); |
CSRF対策をするには?
CSRFとは「クロスサイトリクエストフォージェリ」といい、他サイトやJavaScriptからリクエストを受け付ける事でアプリケーションに脆弱性を生み、そこを攻撃する方法です。
信頼できるページしかリクエストを受け付けないようにすることで対策を行います。
RailsではデフォルトでCSRF対策を行っています。
どうやって信頼できるページなのかを判断しているかというと、Railsには「<%= csrf_meta_tags %>」というヘルパーメソッドが用意されていて、HTMLに「CSRFトークン」と呼ばれる認証鍵のようなものを渡すことが出来ます。
生成されたHTMLを確認すると下のように文字列が取得されている事が分かります。
Railsの用意したヘルパーメソッドを利用してSubmitを行った場合、Railsに受け渡すデータと一緒にこのトークンも受け渡されます。
トークンが一緒に渡ってこないと、「422 Unprocessable Entity」というエラーとなり、リクエストははじかれます。
Ajax通信の場合も同様に、この「CSRFトークン」を一緒に渡してあげる必要があります。
ソースはこちらの記事を参考にしました
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/** * CSRFトークンを取得・セット */ function set_csrftoken() { $.ajaxPrefilter(function (options, originalOptions, jqXHR) { if (!options.crossDomain) { const token = $('meta[name="csrf-token"]').attr('content'); if (token) { return jqXHR.setRequestHeader('X-CSRF-Token', token); } } }); } function ajax() { // ajax通信条件にCSRFトークンを入れる set_csrftoken() $.ajax({ url: "/root/set_message", type: "POST", data: params }) // 以下省略 } |
まとめ
ajax通信は便利ですが、何かと自分で設定するところが多く、自分の脳がRailsに依存しきってるんだなと思い知らされました。
次回は、今回の内容を少し発展させてRailsでAPIの作り方について紹介したいと思います。