インクリメンタルサーチを実装  ajax　jQuery rails　初心者むけ

<h1>インクリメンタルサーチを実装する！</h1>
インクリメンタルサーチとは・・逐次検索です！

<h2>完成イメージ</h2>
あるワード「コロナ」を入れると、、そのワードがタイトル、コンテンツ内に含まれてる記事が出てきます。
さらに、「コロナ」から「コロナウイルス」にうち進めると...
さらに絞り込まれていきます。
ちなみに下に出てくる記事のタイトルは、リンクにしてるので
押したらそのまま、記事に飛べます。

頑張って実装したのでまとめていきます:fist:


![スクリーンショット 2021-08-20 20.49.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633266/a6f5040a-bc90-691b-a797-488f0f4a7e47.png)
![スクリーンショット 2021-08-20 20.49.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633266/1e700ca7-22df-1dde-0012-35bc60ecb443.png)
![スクリーンショット 2021-08-20 20.50.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633266/1ae00580-682b-cbce-caf6-4399611d4252.png)

<h2>まずは通常の検索機能を実装します</h2>

以下の記事を参考に実装しました。

https://qiita.com/Masanori_N/items/5065bc59d9dff88d5152

検索対象をタイトルとコンテンツにしたかったので、
モデルファイルはこんな感じにしてあります。


```perl/model/post.rb
def self.search(search)
    return Post.all unless search
    Post.where('title LIKE(?)', "%#{search}%").or(Post.where('content LIKE(?)', "%#{search}%"))
end
```

さて、通常の検索機能がしっかり動くことを確認したら、
インクリメンタルサーチを実装していきます！！

<h2>Gem等の準備</h2>

```perl:Gemfile
gem 'jquery-rails'
```
gem入れたら```bundle install```

application.jsに
```//= require jquery```入れます。

```perl:application.js
//= require jquery
//= require jquery3
//= require popper
//= require bootstrap-sprockets

//= require summernote/summernote-bs4.min
//= require summernote-init


//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require_tree .
```

<h2>検索窓の編集</h2>

```perl:posts/_index.html.erb
 <div style="text-align:center;">
      <h6><i class="fas fa-search">投稿記事を探す</i></h6>
    </div>
      <%= form_with(url: posts_searches_path, local: true, method: :get, class: "search_form_posts") do |f|%>
      <%= f.text_field :posts_keyword, placeholder:"キーワード", class: "search_input_posts"%>
      <%= f.submit "検索", class: "search_btn"%>
      <% end %>
    　　    <ul id="result_posts">
          </ul>
```
ここで大事なのは、クラス名の指定と、検索ワードを:posts_keywordで受け取るように
してるところでしょうか。
１つのアプリケーションで、部署検索、ユーザー検索のインクリメンタルサーチを
行ったのでごっちゃにならないようにしています。
```<ul id="result_posts">```ここは、
インクリメンタルサーチの検索候補が出てくるところです！


```perl:controllers/posts/searches_controller.rb
class Posts::SearchesController < ApplicationController
  def index
    posts = Post.search(params[:posts_keyword])
    @posts = posts.page(params[:page]).per(25)
    @value = params[:posts_keyword]
    @tag_list = Tag.order('id DESC').limit(20)
    respond_to do |format|
      format.json { render 'posts/index', json: @posts }
      format.html
    end
  end
end
```

```posts = Post.search(params[:posts_keyword])```
ここは、検索ワードを受け取る部分です。
Post.searchとなっているように、ここで検索ワードをpostモデルに渡して、
検索をかけています。
```@posts = posts.page(params[:page]).per(25)```
その検索結果が@postsに入ります。
```@value = params[:posts_keyword]```
ここは検索結果の表示画面で、
「〜〜の検索結果です。」と表示したいので定義してます。
そして、問題は以下ですね・・・

```rb
respond_to do |format|
      format.json { render 'posts/index', json: @posts }
      format.html
    end
```
json形式のデータを受け取ったら、
@postsをデータとして返し、render indexします　という記述です。
ちなみに、 { render 'posts/index', json: @posts }書かないと、
何も起こらなくなってしまいますので忘れずに。

<h6>json形式って何？？</h6>
Javascriptと相性が良い、ファイルの書き方のルールだそうです！
Javascript Object Notationの略です。

ちなみに、json.jbuilderを作成しているインクリメンタルサーチの
記事がありますが、今回の場合なくてもできます。
（あれを使うともっと高度なインクリメンタルサーチを作れるのでしょうか・・）

<h2>Javascriptを書いていく</h2>
namespace使ってるので、フォルダとファイルは以下の状態です。

![スクリーンショット 2021-08-20 22.12.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633266/0ddb4ad1-6b3b-7031-d4b4-b0773a79b1cb.png)

jsファイルは手動で作成したような気がします。。

javascript書いてると、すごく、警告マークみたいなのが出てきます:frowning2:
気にせず進めます・・・

![スクリーンショット 2021-08-20 22.15.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633266/03cd1a50-7bb7-717a-c59b-63c2972007f8.png)


```perl:posts/search.js
// ターボリンクの個別無効化
$(document).on('turbolinks:load', function(){
// このアプリ（document)で、searc_inputで入力されるごとに、eという引数受け取る
  $(document).on('keyup', '.search_input_posts', function(e){
// キャンセル可能なイベントをキャンセル
    e.preventDefault();
// 入力された言葉を取得し、前後の余白をtrimで取り除き、inputに代入する
    var input = $.trim($(this).val());

// 非同期通信・行う場所・メソッド等、jsonで渡す
    $.ajax({
      url: '/posts/searches',
      type: 'GET',
// コントローラーに渡す値を入力された値にする
      data: ('posts_keyword=' + input),
      processData: false,
      contentType: false,
      dataType: 'json'
    })
// 通信が成功した時の処理が以下
    .done(function(data){
// idがresultの子要素liを削除する
    $('#result_posts').find('li').remove();
// dateをuserという変数に代入し以下を繰り返し処理する
    $(data).each(function(i,post) {
    $('#result_posts').append(`<li class="post"><a href="/posts/${post.id}">${post.title}</a></li>`)

});
    })
  });
});
```

:point_up:```$(document).on('turbolinks:load', function(){```
なんかjQueryがうまく動かないなーというときはこれが原因らしいので、
このように無効化します。個別に無効化するのがベストです。

:v:```var input = $.trim($(this)```で、前後の空白を取り除きます。
仮に、```var str = ' foo ';
console.log(str.trim());```であれば出力はfooになります。

:point_up:```this```は、.search_input_postsを呼び出しています。

:v:```val());```は、HTML要素の値を取得、変更したりしてくれます。
ユーザーがフォームに入力した内容や選択した項目を
jQuery側から把握できるようにしています。

:point_up:('#result_posts').find('li').remove()は、
検索窓の```<ul id="result_posts"></ul>```ここを指しています。
liタグはulタグの中に入ってる検索結果です。
ここを書かないと何も書いてない状態で、全記事のタイトルが、出てきてしまうかと思います。
なので一旦削除します。

:v:```$(data).each(function(i,post) {```
ここで、データを取り出して、postという変数に代入し、それ以降の作業を繰り返し行なっています。
```(data).each(function(i,post)```はjQueryのeachメソッドです。

```$('#result_posts').append(`<li class="post"><a href="/posts/${post.id}">${post.title}</a></li>`)```
append(content)で、要素である('#result_posts')にcontentsを追記していきます。

https://into-the-program.com/loop-object-each/

http://semooh.jp/jquery/api/manipulation/append/content/



<h2>参考にした記事</h2>

https://qiita.com/yuki-n/items/fdc5f7d5ac2f128221d1

<h2>難しい・・・</h2>

難しいですが、、頑張って１歩ずつ進んでいきます:frowning2: