Rails 증분 검색

소개



이번에는 증분 검색에 대해 쓰고 싶습니다.
Rails 무한 스크롤 (gem, 라이브러리 없음) 때 작성한 샘플 어플리케이션에 기능을 추가해 갑니다. (전제 조건(무한 스크롤 실장 전) 시점부터 작업 개시)

증분 검색이란?



응용 프로그램에서 검색하는 방법 중 하나. 검색하고 싶은 단어를 모두 입력한 후에 검색하는 것이 아니라, 입력할 때마다 즉시 후보를 표시시킨다. 순어 검색, 순차 검색 모두.

인용
Wikipedia

완성 이미지





증분 검색 기능 만들기



우선은 보통의 검색 기능을 작성해, 그 후 인크리멘탈 검색 기능으로 변경해 가고 싶습니다.

처리 흐름
  • #index에서 books 목록보기
  • 검색 기능 구현
  • 검색 창에 키 조작을하면 이벤트 발화
  • #index에 검색 키워드를 보내고 레코드를 가져옵니다
  • jbuilder에서 json 형식으로 변환하고 데이터를 반환합니다.
  • 반환 된 데이터를 바탕으로 js 측에서 처리

  • 4. 이후는 jbuilder를 이용하지 않는 방법으로도 구현 가능합니다. 이 기사 에 기재되어 있습니다.

    구현

    1.#index에서 books 일람을 표시

    index.html.erb를 부분 partial화합니다.

    app/views/books/index.html.erb
    <h4>新規投稿</h4>
    <div class='scroll__new'>
      <%= render 'new', book: @book %>
    </div>
    
    <h4>投稿一覧</h4>
    <table class='scroll__table'>
      <thead>
        <tr>
          <th class='scroll__th'>タイトル</th>
          <th class='scroll__th'>内容</th>
        </tr>
      </thead>
      <tbody class='scroll__tbody'>
        <%= render 'index', books: @books %>
      </tbody>
    </table>
    

    app/views/books/_index.html.erb
    <% books.each do |book| %>
      <tr>
        <td class='scroll__td'><%= book.title %></td>
        <td class='scroll__td'><%= book.body %></td>
      </tr>
    <% end %>
    

    2. 검색 기능 구현

    1. 검색창 만들기

    app/views/books/index.html.erb
    <div class='search'>
      <%= form_with url: books_path, method: :get do |f| %>
        <%= f.text_field :key_word, placeholder:'キーワード', class:'search__word' %>
        <%= f.submit '検索'%>
      <% end %>
    </div>
    

    2. 검색 기능 만들기

    app/models/book.rb
    # 検索結果を返す
    def self.search(key_word)
      if key_word == ''
        books = Book.all
      else
        books = Book.where(['title LIKE(?) OR body LIKE(?)', "%#{key_word}%", "%#{key_word}%"])
      end
    end
    

    title과 body 모두에서 검색할 수 있도록 합니다.

    app/controllers/books_controller.rb
    class BooksController < ApplicationController
    
      def index
        key_word = params[:key_word]
        @books = Book.search(key_word)
        @book = Book.new
      end
    end
    

    app/views/books/index.js.erb
    $('.scroll__tbody').html('<%= j(render 'index', books: @books) %>');
    

    #index는 동기 통신과 비동기 통신 요청을 모두 수신하므로 index.html.erb와 index.js.erb를 작성합니다. 이해하기 어려운 경우는 액션을 나누어 주시면, 알기 쉬워진다고 생각합니다.
    이상으로 검색 기능의 작성은 종료입니다.

    3. 검색창에 키 조작을 하면 이벤트 발화

    여기에서 증분 검색을 구현하고 싶습니다.
    검색창에서 input 이벤트를 검출한 타이밍에서 처리합니다.

    app/assets/javascripts/search.js
    $(document).on('turbolinks:load', function() {
      $(document).on('input', '.search__word', function(){
        // 処理を記述
      });
    });
    

    4. #index에 검색 키워드를 보내 레코드를 가져옵니다.

    처리 내용을 써 갑니다.

    app/assets/javascripts/search.js
    $(document).on('turbolinks:load', function() {
      $(document).on('input', '.search__word', function(){
        // tbodyの中身を一度空にする
        $('.scroll__tbody').html('');
        // 検索ワードの取得
        const key_word = $(this).val();
        // #indexにajax通信
        $.ajax({
          type: 'GET',
          url: '/books',
          data: {key_word: key_word},
          dataType: 'json'
        })
        .done(function(data){
          // 返ってきたdataに対して処理を実行
        })
      });
    });
    

    5.jbuilder에서 json 형식으로 변환하고 데이터를 반환합니다.

    app/views/books/index.json.jbuilder
    json.array! @books do |book|
      json.title book.title
      json.body book.body
    end
    

    jbuilder에서의 변환 예는 여기에 몇가지 실려 있습니다만, 검색하면 기사도 많이 나오므로, 그쪽이 알기 쉽다고 생각합니다.

    6. 돌아온 데이터를 바탕으로 js 측에서 처리

    app/assets/javascripts/search.js
    // .done(function(data)の中身
    // 返ってきたdataに対して処理を実行
    data.forEach(function(data){
      const html = `
        <tr>
          <td class='scroll__td'>${data.title}</td>
          <td class='scroll__td'>${data.body}</td>
        </tr>
      `;
      $('.scroll__tbody').prepend(html);
    });
    

    최종 search.js 코드는 여기

    app/assets/javascripts/search.js
    $(document).on('turbolinks:load', function() {
      $(document).on('input', '.search__word', function(){
        // tbodyの中身を一度空にする
        $('.scroll__tbody').html('');
        // 検索ワードの取得
        const key_word = $(this).val();
        // #indexにajax通信
        $.ajax({
          type: 'GET',
          url: '/books',
          data: {key_word: key_word},
          dataType: 'json'
        })
        .done(function(data){
          data.forEach(function(data){
            const html = `
              <tr>
                <td class='scroll__td'>${data.title}</td>
                <td class='scroll__td'>${data.body}</td>
              </tr>
            `;
            $('.scroll__tbody').prepend(html);
          });
        })
      });
    });
    



    이상으로 증분 검색의 기능 구현은 종료입니다.

    좋은 웹페이지 즐겨찾기