Ajax非同期通信をRailsで使う

先週散々頭を悩まされ続けてきた、「選択した会社名に応じて売上発生原因の項目をajaxで変更する。」という課題を何とかするために、丸一日使って、同じような仕組みを実装してみた。

お題を少し変えて、「大学名に応じて、選択する学部名を変える」というものにした。

github.com

(function (){
    $("#univerisities").change(function(){
        var value = $("#univerisities").val();

      function getParam(){return $.ajax({
             url: "/articles/ajax_department",
             type: "GET",
             data: {id: value},
             dataType: "script",
             success: function(data) {alert("success");},
             error: function(data) {alert("error");}
         });}

         getParam().done(function(result) {
            console.log(result);
        }).fail(function(result) {
           console.log(result)
        });
    })
})

JQueryを使って、プルダウンメニューの変更探知もかなりシンプルに書くことが出来る。また、非同期の通信、つまり通信の終了時の動作は自分で書くことを求められ、それがgetParam.done()になっている。

で、このJSのコードでコントローラのアクションを叩き、これによって、プルダウンメニューのオプションを変えるのに必要なアクション名.js.erbが返される。

  respond_to do |format|
      format.js
  end

js.erbはサーバー側で、erb部分が適当な値にレンダリングされ、純粋なjavascriptとしてクライアント側に返される。

$("#replace").html('<%= j select_tag 'univerisities', grouped_options_for_select(@departments,nil,prompt: "学部を入力してください。") %>')

上のコードの場合、@departmentsはコントローラで取得したJSONの配列に置き換わる。

この時、select_tagの前に「j」を付けないと「invalid or unexpected token」となる。このエラーは別のファイルとして読み込んでいる場合、コンソールにも表示されない。自分はjs.erb自体が読み込まれていないのではないかと悩み、これに3時間ほど頭を悩ませた。

stackoverflow.com

プルダウンメニューはreplaceというdivで囲ってあり、それをターゲットとしてhtmlの書き換えを行っている。

ちなみに、JSONの配列は

SELECT_UNIVERSITIES = [["大学",[
          ["明治大学",1],
          ["立教大学",2],
          ["青山学院大学",3],
          ["法政大学",4],
          ["中央大学",5],
          ["学習院大学",6]
        ]
       ]]

大項目が一つしかない場合でも、それ一つを配列の1つ目として扱わなくてはならない。また、複数の選択肢全体で一つの配列を形成していなくてはならない。

これを売上計上原因に応用するとこんな感じになり、

SalesReasons = [
                      ["増加",[]],
                      ["売上",[["テスト売上",1],["その他",2]]],
                      ["減少",[]],
                      ["売上",[["課税売上高",1],["その他",2]]]
                    ]

それをselect_tagとgrouped_options_for_selectタグを使って分類するとこんな感じで仕上がる。
f:id:Pyons:20190317215203p:plain

このJSONJSON fomatterを使うと文法ミスにされるんだけど、railsで読み込ませてみたらちゃんと使えた。