トップイメージ

ajaxでサーバーからデータを受け取って・・・その後の描画は?

しばらく前からRailsを触られてきた方ならば、フロント側でjqueryを使われているかたも多いと思います。 筆者もjqueryを仕事で使っており、ajaxを使ってサーバー側にデータを送り、その返り値をクライアント側に描画するという動作をよく使います。

よく使うのが、

  • サーバーからデータを受け取る
  • viewに用意している要素にjqueryでセレクタを指定して、値を入れていく
    • $('セレクタ').val(('サーバーからの返値')); や
    • $('セレクタ').html(('

      サーバーからの返値

      '));

といった動きです。

これが上のような単純なものであれば良いのですが、例えば「段組をしたテーブルを描画しろ」 とか「無駄に洗練された無駄のないコードで複雑なhtmlを生成しろ」とか言われた日には、めんどくさくて吐きそうになります。😢

Railsには各種フォームへルパーメソッドを始め、view側でもRubyのコードをかける機能がありますが、jqueryで↓のような記述をしても、当然jqueryでRailsのフォームへルパーを解釈して描画することなどできません。

//ダメな例。当然Railsのメソッドはjsでは解釈できない
$('#target').html('<%= telephone_field_tag :test,:id,value:"1",id:"id1",class:"form-control" %>')

//やるならこう。
$('#target').html('<input type="tel" name="test" id="id1" value="1" class="form-control">')

せっかく、Railsにはパーシャル(部品化)やフォームを楽にかけたり、繰り返し処理を簡単にかけるんだから、その利点を活かしつつ、jquery + ajaxで動的にページを更新したい、というのが今回の目的です。

早速コードを

今回はこのようなページを用意して、テキストボックスに入れた数値をajaxで送信すると、そのidを持つユーザーをページ遷移なしで表示するようにしてみます。

before after

Rails側

#パーシャル(_list.html.erb)
<div>
    <h2>ここからがパーシャルだよ</h2>
    <% if @user_list.present? %>
    <p>部分更新されたので、DBから受け取った人の名前が表示されるよ<p>
        <ul>
            <% @user_list.each do |user| %>
                <li><%= "#{user.name}(#{user.name_kana})" %></li>
            <% end %>
        </ul>
    <!-- 初期では↓が表示され、ajaxで↑を表示する -->
    <% else %>
        <p>初期値だよ。ajaxで部分更新するとユーザーの名前が取れるよ</p>
        <p>ここにユーザーIDを3つ入れて送ってみるとな・・・</p>
        <div class="col-sm-4">
            <%= telephone_field_tag :test,:id,value:"1",id:"id1",class:"form-control" %>
            <%= telephone_field_tag :test,:id,value:"2",id:"id2",class:"form-control" %>
            <%= telephone_field_tag :test,:id,value:"3",id:"id3",class:"form-control" %>
        </div>
        <a href="javascript:void(0)" type="button" id="id_submit" class="btn btn-save"><i class="material-icons">save</i>ajax!</a>
    <% end %>
</div>
#パーシャルを呼び出すview
<h1>ajaxを使ってページ遷移なしでパーシャルを更新しよう!</h1>
    <div id="target">
        <%= render :partial => "list", locals:{user_list: @user_list} %>
    </div>
<%= javascript_pack_tag 'test.js' %>

#ルーター
resources:test do
    collection do
      #ajaxを行うルートの設定
      post 'search'
    end
  end
#コントローラー
class TestController < ApplicationController
  def index
    @user_list = nil
  end

  def search
    #例
    id_list = params[:id_list]
    @user_list = []
    id_list.each do |id|
      @user_list.push(User.find(id))
    end
    #ここが肝!render_to_stringで変数を渡した状態で文字列に変換しちゃおう    
    partial = render_to_string(partial:'list', :locals => { user_list: @user_list })
    puts partial
    render json:{html:partial}
  end
end

↑のコントローラ処理が重要です

結局、Railsのヘルパーメソッドでerbの中でRubyのeach文を使ったりしていますが、 このメソッドで戻り値として返されるのが、↓のようなhtmlタグです。

<!-- Railsで解釈されこのようなhtmlが生成されている -->
<div>
    <h2>ここからがパーシャルだよ</h2>
    <p>部分更新されたので、DBから受け取った人の名前が表示されるよ</p><p>
        </p><ul>
                <li>金沢 均(かなざわ ひとし)</li>
                <li>落合 安未(おちあい やすみ)</li>
                <li>浅野 克之(あさの かつゆき)</li>
        </ul>
            
</div>

今回は、Railsのコントローラー側で、パーシャルをhtmlタグとしてRails側に変換してもらい、それをrender_to_stringで文字列情報としてajax通信でjs側に渡しています。

js

$(function(){
    $('#id_submit').on('click',function(){
        //テキストボックスの入力値をサーバーへ送る
        var id_list = [$('#id1').val(),$('#id2').val(),$('#id3').val()];
        $.ajax({
            url: '/test/search',
            dataType: 'json',
            type: 'POST',
            data:{
                id_list:id_list
            },
          }).done(function(result) {
            //今呼び出しているパーシャルを消して、受け取ったパーシャルを表示
            $('#target').children().remove();
            $('#target').html(result.html);
          }).fail(function(err){
              console.log(err);
          })
    })
})

と、このような形でRailsのパーシャルやヘルパーメソッドを有効に活用しつつ、jqueryでページ遷移なしの動きを実装してみました。

今回はものすごく簡単な例ですが、決まったテンプレートをRailsの機能を使って記述したいときに役立ちます。

無論、これでは対応できない事例や、partialを作るまでもない変更等は別途対応する必要があります。