&tag(Rails/Ajax);
*目次 [#n755f4d8]
#contents
*関連ページ [#w18db114]
-[[Rails]]
-[[Rails/検証]]

*参考情報 [#zcba7473]

-[[Rails / Ajaxを使って画面遷移しない一時保存機能をつける | Workabroad.jp:http://www.workabroad.jp/posts/2091]]
-[[Ruby - RailsでAjaxを使ってインクリメンタルサーチ - Qiita:http://qiita.com/Kta-M/items/99003e6d9d98b0ba512f]]
-formの内容をcommitしたい場合、[[jQuery Form Plugin:http://malsup.com/jquery/form/]]のような便利なライブラリを使ったほうが便利。

*インクリメンタル検索の実装 [#ubc92a8e]
**フォームとJavaScript [#j217fe3c]
-ransackを使った検索フォーム
#pre{{
<!-- 検索フォーム部分 -->     
      <%= search_form_for(@search) do |f| %>
          <%= f.text_field :title_cont, {:placeholder => '検索'} %>
      <% end %>
}}
-JavaScript部分。jQueryを使用して一定時間ごとにイベントを送信する。データの送信にはjQuery Form PluginのajaxSubmitを使う。
#pre{{
<!-- JavaScript部分 -->     
<script type="text/javascript">
  // 内容の自動保存処理
  var preFunc = null;
  var preInput = ''
  var input = '';
  var timeoutValue = 10;

  ajaxPost = function() {
    $("#book_search").ajaxSubmit({
      url: '/books/',
      type: 'get'
    });
  }

  $('#q_title_cont').on('keyup', function () {
    input = $.trim($(this).val());   //前後の不要な空白を削除
    if (preInput !== input) {
      clearTimeout(preFunc);
      preFunc = setTimeout("ajaxPost()", timeoutValue);
    }
    preInput = input;
  });

</script>
}}
-コントローラー。通常検索件Ajaxを処理する場合respond_toでformat.jsを先に書かないとindex.js.erbが呼ばれないかも?
#pre{{
  def index
    @books = @search.result.page(params[:page])
    respond_to do |format|
      format.js {}
      format.html {}
    end
  end
}}
-index.js.erb。もともとのコンテンツを隠し検索結果を表示する。
#pre{{
$("#main_content").hide();
$("#booklist_list").show();
$("#booklist_list").html("<div class='well'><h2>インクリメンタル検索</h2></div><%= escape_javascript(render 'shared/search_book_list') %>");
}}
*フォームの内容の自動保存する [#oec0ecd3]
-[[Rails / Ajaxを使って画面遷移しない一時保存機能をつける - Qiita:http://qiita.com/shunwitter/items/bdad11ec7d4a99ca3d3b]]より。
**フォームの入力フィールド [#e8da407e]
-class="create-temp"のdivがポイント
#pre{{
<div class="blog-form">
    <%= form_for(@post) do |f| %>

        <%= f.text_field :tilte %>
        <%= f.text_area :body %>
        <!-- for temporal saving -->
        <div class="create-temp"></div>
        <%= f.submit "送信する" %>

    <% end %>
</div>
}}

**フォームの送信処理部分(JavaScript版) [#i4e5cc2d]
-submit用に[[jQuery Form Plugin:http://malsup.com/jquery/form/]]を使う。
-keydownにより何か変更があったら5秒後に送信されることになる。
-spanのdeta-result属性がtrueでない場合はcreate-tempを、trueの場合はupdateを呼び出すようにする。

#pre{{
    var ready, tempSubmit;

    ready = function() {
        if ($('.create-temp')) {
            window.tempTimer = null;
            return $('.blog-form form').keydown(function() {
                window.clearTimeout(tempTimer);
                return window.tempTimer = window.setTimeout(function() {
                    return tempSubmit();
                }, 5000);
            });
        }
    };

    tempSubmit = function() {
        if ($('.create-temp span').data('result') !== true) {
            return $(".blog-form form").ajaxSubmit({
                url: '/posts/temp',
                type: 'post'
            });
        } else {
            return $(".blog-form form").ajaxSubmit();
        }
    };

    $(document).ready(ready);
    $(document).on('page:load', ready);

}}
**routes.rb [#b1676ad0]
-上記JavaScriptでPostしているrouteをを作成。
#pre{{
  post '/posts/temp', to: 'posts#create_temp', as: :temp_post
}}
**コントローラー [#kf46062d]
-createは通常の保存処理。create_tempからajaxから呼ばれるメソッド。
#pre{{
  def create
    @post = Post.new(post_params)

    if @post.save
      redirect_to(@post)
    else
      render('new')
    end

  def create_temp
    @post = Post.new(post_params)
    @post.save
  end


  def update
    respond_to do |format|
      if @post.update(post_params)
        format.js {}
        format.html {redirect_to @post, notice: 'Post was successfully updated.'}
      else
        format.js {}
        format.html {render :edit}
      end
    end
  end
}}
** レスポンス用のjs.erb[#va8d45d5]
-create_temp.js.erbの内容
#pre{{
var result = <%= @post.valid? %>;
var msg = "";
var notice = "";

if (result == true) {
    msg = "下書き保存されました";

    // This is for Temporal saving
    // forcing the form to look update method.

    // Add id
    $('.blog-form form').prepend('<input name="post[id]" type="hidden" value="<%= @post.id %>">');

    // Chnage REST method
    $('.blog-form input[name=_method]').remove();
    $('.blog-form form').prepend('<input name="_method" type="hidden" value="patch">');

    // Change URL
    $('.blog-form form').attr('action', '/posts/<%= @post.id %>');

} else {
    msg = "下書き保存のための情報が足りません";
}


// Message
notice = "<span data-result=" + result + ">" + msg + "</span>";
$('.create-temp span').remove();
$('.create-temp').hide().append(notice).fadeIn();

}}
-update.js.erbの内容。
#pre{{
var persisted = <%= @post.persisted? %>;
var result = <%= @post.valid? %>;
var msg = "";
if (result == true) {
    msg = "下書きが更新保存されました";
} else {
    msg = "下書き更新保存のための情報が足りません";
}
// Message
notice = "<span data-result=" + persisted + ">" + msg + "</span>";
$('.create-temp span').remove();
$('.create-temp').hide().append(notice).fadeIn();

}}

*flashメッセージの取り扱い [#ya8fb586]
-通常のrequestと取り扱いがことなるためajax_requestで設定したメッセージが2重に表示されたりする場合がある。
-[[How do you handle Rail's flash with Ajax requests? - Stack Overflow:http://stackoverflow.com/questions/366311/how-do-you-handle-rails-flash-with-ajax-requests]]
-これを回避するためにApplicationControlerにafter_filterを設定する。
#pre{{
  after_filter :clear_flash

  private
  def clear_flash
    flash.discard if request.xhr?
  end
}}

*トラブルシューティング [#jb3edf89]

**js.erbがレンダリングされない [#r8751e38]
-例えばupdateメソッドでupdate.js.erbが実行されない。
-以下のようにresponde_toで、「format.js {}」を追加する必要がある。
-さらにformat.jsが、format.htmlより先にないとだめかも?
#pre{{

  def update
    respond_to do |format|
      if @post.update(post_params)
        format.js {}
        format.html {redirect_to @post, notice: 'Post was successfully updated.'}
      else
        format.js {}
        format.html {render :edit}
      end
    end
  end
}}

** ActionController::UnknownFormatエラーが発生する [#e849275b]
-コントローラーにビューから呼び出されるメソッドは存在するものの以下の部分でエラーが発生する。
#pre{{
    respond_to do |format|
      format.js { }
    end
}}
-このrespond_to自体がなくても改善しない。原因としてありがちなことはviewで「remote: true」を指定しなかったこと。
-あるいはJavaScriptを使ってonclickでsubmit()処理を実行しているとうまくいかない。viewがノーマルな設定(submit処理)になっているかどうか確認する。


トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS