Timeless search with Rails + JavaScript (jQuery)

Search function handled in articles

It is a search function like this. This time, we will extract the column named name from the table called shops and display it in the view.

edc53a4c67fcde418466da618219084f.gif

--Asynchronous --Search and draw each time you type a character --Click the search result to link to the corresponding page

Probably, I think that the knowledge level and common sense level in programming for beginners are much lower than those thought by experienced people. So, I think I'll write as much as I can, "Is it necessary to explain such a thing?"

Development environment

mac Ruby 2.5.1 Rails 5.2.3 jQuery

Required files

First, the files required for implementation are summarized below.

--Preparation of ** controller ** that defines the action to search

app/controllers/shops_controller.rb


 def search
 end

--Preparation of ** json.jbuilder ** corresponding to the above action

ruby:views/shops/search.json.jbuilder


#Pay attention to directory relations and file names to correspond to the controller and action created above
#In this case, views/shops(Corresponds to the controller name)/search(Corresponds to action name).json.jbuilder

--Preparing ** Routing ** for the above actions

config/route.rb


resources :shops do #in the shops controller
 collection do
  get 'search'      #search action
 end
end

--Preparing a ** view ** file to display the search form and results

ruby:app/views/shops/index.html.haml


#This time, the search is displayed on the shops list screen.
#I will write using haml, but it can be normal html or slim.

-** js ** File preparation

app/assets/javascripts/search.js


#.The name can be anything as long as it ends with js

As mentioned above, we will implement the search function using 5 files.

How does it work?

The flow of the search process is as follows.

Receive the event that occurred in the search form as a .js file.

○○.html.haml(○○.html.erb) → ○○.js

Send the received information to the controller in json format.

○○.js → ○○_controller

Extract the necessary information from the DB with the controller and convert it with jbuilder so that it can be used in .js.

○○_controller → ○○.json.jbuilder

Send it to the js side again and draw it in html.

○○.json.jbuilder → ○○.js → ○○.html.haml

If you don't know the process flow, you can't deal with an error and waste an hour or two. I will explain as much as possible in the actual code that I will write, so please read it with the above processing flow in mind.

Let's get started.

Do the routing

This time, as an example, set the ** search ** action inside ** shops_controller **.

app/controllers/shops_controller.rb


 def search
 end

config/route.rb


resources :shops do #in the shops controller
 collection do
  get 'search'      #search action
 end
end

Preparation of search form and result display field

ruby:app/views/shops/index.html.haml


.search-field
 .fas.fa-search  #I'm using fontawesome with magnifying glass.
 .shop_search
   = f.text_field :text, placeholder: "Search by store / address", id: "shop_search"  #A text input field is set up.
 #shop_search--result ← shop instead of commenting out_search--The id name is result. Display search results.
   .shop-search-list

Receive the information entered in the search form and send the received information to the controller

app/assets/javascripts/search.js


$("#shop_search").on("keyup", function(){
  let input = $("#shop_search").val();
  $.ajax({
   type: 'GET',
   url: '/shops/search',
   data: {keyword: input},
   dataType: 'json'
  })

First, you will receive the information entered in the search form (f.text_field in the haml file) as a js file. ┗ Specify the id name given to the search form, and get the information with key up the moment you speak your finger from the keyboard when entering characters.

The information below ajax ·how ·where ·what ・ In what condition Specify whether to send.

In this case, I think that the GET method will send the input to the search action in the shops controller in the json method.

Describe the action setting and interaction with the DB on the controller

app/controllers/shops_controller.rb


  def search
    return nil if params[:keyword] == ""
    @shops = Shop.where('name LIKE ? OR location LIKE ?', "%#{params[:keyword]}%", "%#{params[:keyword]}%").limit(10)
    respond_to do |format|
      format.html
      format.json
    end
  end

This time I set the name (store name) column and location (location) column when creating the shops table, so I set it so that I can search with these two information, For example, if you want to search by store name only,

app/controllers/shops_controller.rb


  def search
    return nil if params[:keyword] == ""
    @shops = Shop.where('name LIKE ?, "%#{params[:keyword]}%").limit(10)
    respond_to do |format|
      format.html
      format.json
    end
  end

Is OK.

** params [: keyword] ** in the action comes from data: {keyword: input} under ajax in the previous js file. It may be difficult to understand, but it means that the characters entered in the search field are treated as input in the js file and as keywords in the controller file. If nothing is entered in the search field (second line ""), nil is returned.

Also, in the 3rd line, the shops table pulls out information from the DB based on that keyword (character entered in the search field). This time, the specification is to perform a partial match search by enclosing the quantity end of params [: keyword] in **% **. For other search methods, please refer to this article.

-Rails-Ambiguous search for characters using LIKE clause (when you want to search for words containing specific characters) I also referred to this article. Thank you very much.

And since the character data entered this time is in the controller in json format, it moves to jbuilder.

Information conversion with json.jbuilder

ruby:search.json.jbuilder


json.array! @shops do |shop|
  json.name           shop.name
  json.location       shop.location
end

I extracted the information from the DB in the controller, but I need to convert this data to json format. Do that with jbuilder.

Drawing search results to html file

First of all, the processing by the controller is completed under the js file ajax earlier, and the processing when returning is added.

app/assets/javascripts/search.js


  $("#shop_search").on("keyup", function(){
    let input = $("#shop_search").val();
    $.ajax({
      type: 'GET',
      url: '/shops/search',
      data: {keyword: input},
      dataType: 'json'
    })
    .done(function(shops){
      $("#shop_search--result").empty();
      if (shops.length !== 0) {
        shops.forEach(function(shop){
          addShop(shop);
        });
      } 
      else if (input.length == 0){
        return false;
      } else {
        addNoShop();
      }
    });
  });

Below .done is the process.

Then, addShop and addNoShop are drawn in html respectively.

Below is the full js file.

app/assets/javascripts/search.js


$(function(){
  function addShop(shop) {
    let html = `
      <a href="/shops/${shop.id} class="shop_search-list">
        <div>${shop.name} - ${shop.location}</div>
      </a>
      `;
      $("#shop_search--result").append(html);
  };
  function addNoShop(){
    let html =`There is no shop`
    $("#shop_search--result").append(html);
  };
  $("#shop_search").on("keyup", function(){
    let input = $("#shop_search").val();
    $.ajax({
      type: 'GET',
      url: '/shops/search',
      data: {keyword: input},
      dataType: 'json'
    })
    .done(function(shops){
      $("#shop_search--result").empty();

      if (shops.length !== 0) {
        shops.forEach(function(shop){
          addShop(shop);
        });
      } 
      else if (input.length == 0){
        return false;
      } else {
        addNoShop();
      }
    })
  });
});

Specify the standard when drawing as let html. This time, I tried to link to the details page when I clicked on the search result.

Insert the fixed phrase (html) created by using append in the place (#shop_search--result) where the search result is displayed in the haml file.

This completes the asynchronous search function (incremental search).

Try it

This content was created by trying the content learned at school by myself and deepening my understanding. At the beginning of the study, I was hoping that I could do it with a half-hearted understanding, but when I started from 1 on my own, I often stopped working. It is a reflection.

I think the point is to understand where and how each file changes. Also, as with any function, in this case it is strongly recommended to continue writing while debugging console.log etc.

Recommended Posts

Timeless search with Rails + JavaScript (jQuery)
[Rails] Book search with Amazon PA API
Rails6 jQuery introduced
[Rails] Use jQuery
Let's make a search function with Rails (ransack)
Rails hashtag search implementation
[Rails] How to search by multiple values ​​with LIKE
Rails deploy with Docker
[Rails 6] RuntimeError with $ rails s
[Rails] Implement search function
[Rails] Learning with Rails tutorial
[Rails] Test with RSpec
Rails search function implementation
[Rails] Development with MySQL
Supports multilingualization with Rails!
Generate JavaScript with Thymeleaf
Double polymorphic with Rails
Back to top button made only with Javascript (rails, haml)
[Rails] Search from multiple columns + conditions with Gem and ransack
Replace Rails favorite feature (Ajax) from jQuery to plain JavaScript
Rails fuzzy search function implementation
[Rails] Implement User search function
Introduced graph function with rails
Search function using [rails] ransack
[Rails] Express polymorphic with graphql-ruby
[Rails] Upload videos with Rails (ActiveStorage)
Try using view_component with rails
[Vue Rails] "Hello Vue!" Displayed with Vue + Rails
Japaneseize using i18n with Rails
API creation with Rails + GraphQL
Preparation for developing with Rails
Run Rails whenever with docker
[Docker] Rails 5.2 environment construction with docker
Use multiple databases with Rails 6.0
[Rails] Specify format with link_to
Login function implementation with rails
Implement search function with form_with
[Docker] Use whenever with Docker + Rails
Handle dates with Javascript (moment.js)
Let's roughly implement the image preview function with Rails + refile + jQuery.
Event firing with JavaScript library JQuery / Ajax (when implementing asynchronous communication)
I tried to implement the image preview function with Rails / jQuery
How to get boolean value with jQuery in rails simple form
[Rails] A memo that created an advanced search form with ransack