[Rails] Implementation of search function using gem's ransack

Background

This portfolio is currently being highly acclaimed, and last time we implemented an ambiguous search function. So, next, I created it with the intention of implementing a search function using gem's ransack. There were many articles that could be helpful, but even so, searching with checkboxes was quite clogged, so I'd like to mention it as a reference for someone.

Please refer to the previous article if necessary. [Rails] How to add fuzzy search function

environment

ruby 2.6.5 Rails 6.0.3.2 haml used

Image diagram

ファイル名 The completed drawing looks like this

procedure

1, introduction of gem 2, create a view of the search form 3, set to controller 4, create a view of search results

There are four steps.

Introduction of gem

First, let's put in a gem quickly.

Gemfile.


gem 'ransack'

It is desirable to list it at the bottom so that there are no strange mistakes.

After inputting, Don't forget to do % bundle install in your terminal% rails s. Don't forget that it will not be reflected unless you rails s!

This completes the gem installation.

Search form view creation

First, from the code The composition consists of (1) keyword search, (2) price search, (3) status search, and (4) shipping charge search.

index.html.haml


.title-box
  %p.title Advanced search
.detail_search--box
  = search_form_for(@q,url: detail_search_items_path) do |f|
    .detail-keyword
      .detail-keyword--box
        %i.fas.fa-plus
        %p.Add wd keyword
      = f.search_field :name_cont, placeholder: "Example) Bike", class: "detail-keyword--form"
    .detail-price
      .detail-price--label
        %i.fas.fa-coins
        %p.wd price
      .detail-price--forms
        = f.search_field :price_gteq, placeholder: "¥ 300 or more", min:300, class: "price-min"
        %p.wd 〜
        = f.search_field :price_lteq, placeholder: "¥ 9999999 or less", max:9999999, class: "price-max"
    .detail-status
      .detail-status--label
        %i.fas.fa-paperclip
        %p.wd product status
      .detail-status--checkbox
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 1, ''
          = 'New, unused'
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 2, ''
          = 'Nearly unused'
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 3, ''
          = 'No noticeable scratches or stains'
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 4, ''
          = 'Slightly scratched and dirty'
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 5, ''
          = 'There are scratches and dirt'
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 6, ''
          = 'Overall poor condition'
    .detail-deliveryFee
      .detail-deliveryFee--label
        %i.fas.fa-truck
        %p.wd shipping charges
      .detail-deliveryFee--checkbox
        .checkboxes
          = f.check_box :delivery_fee_id_eq_any, { multiple: true }, 1, ''
          = 'postage included(Exhibitor burden)'
        .checkboxes
          = f.check_box :delivery_fee_id_eq_any, { multiple: true }, 2, ''
          = 'Cash on delivery(Buyer burden)'
    .detail-btn
      = f.submit "Search", class: "sbt-btn"

Now, let's explain the code.

= search_form_for(@q,url: detail_search_items_path) do |f| When creating a normal form, use form_for and form_with, but when creating a search form with Lansack, use the search_form_for method </ b>. Well, if you use Ransack, you should understand that you should use search_form_for.

Next, I took @q as an argument of search_form_for. We will search based on the query information of @q. This will be defined later in the controller.

And, regarding the url setting part, this is the path to the location where the search results are displayed, so please change it as appropriate. This time, the search results are displayed in detail_search.html.haml, so write the plefix set by routing. When writing plefix as a path, add _path to the end of the character. To find out, use % rails routes in the terminal.
① Search by keyword This part in code

.detail-keyword
  .detail-keyword--box
    %i.fas.fa-plus
    %p.Add wd keyword
  = f.search_field :name_cont, placeholder: "Example) Bike", class: "detail-keyword--form"

The characteristic of the search using Ransack is the _cont part of the ": name_cont" that follows. By the way,: name is the column name. So please change it accordingly. In addition, which table (model) column data to acquire is set by the controller. Returning to the story, this means doing a partial match search using the Like clause on the name column. To make it easier to understand and imagine, it means to search and extract data that contains the keyword (for example) mandarin orange in the name column.

The _cont part is called a predicate in Ransack, and I will list some predicates that are likely to be used frequently.

predicate meaning
*_eq Extract the exact match.
*_in Extracts what is contained in the given array.
*_cont Extracts those that contain strings.
*_lteq Extracts less than a certain value.
*_gteq Extracts anything larger than a certain value.

② Search by price This part in code

.detail-price
  .detail-price--label
    %i.fas.fa-coins
    %p.wd price
  .detail-price--forms
    = f.number_field :price_gteq, placeholder: "¥ 300 or more", min:300, class: "price-min"
    %p.wd 〜
    = f.number_field :price_lteq, placeholder: "¥ 9999999 or less", max:9999999, class: "price-max"

What needs to be explained here is the _gteq part of": price_gteq "and the _lteq part of ": price_lteq" that follow. This is also written in the table above, _gteq extracts more than a certain value, _lteq means to extract less than a certain value. The point is to extract the price column that is larger than 300 (for example) and smaller than 2000.

③ Status search This part in code

.checkboxes
  = f.check_box :status_id_eq_any, { multiple: true }, 1, ''
  = 'New, unused'

(Omitted)

.checkboxes
  = f.check_box :status_id_eq_any, { multiple: true }, 6, ''
  = 'Overall poor condition'

It's a bit confusing here, or it may be a poor explanation because I don't understand it properly.

First of all, it is the _eq_any part of": status_id_eq_any "at the back. The _eq part, as it is also written in the table above, _eq means to extract the exact match. Then, when you say _any, you have to add this if there are multiple cases. This time, there are 6 checkboxes, so it is _eq_any. And "multiple: true" is also needed for the same reason. If you use multiple checkboxes, you must include this. By describing this, the variables of the data will be recognized as an array. The data actually sent as parameters: ["1", "", "", "", "", ""] The ones listed in numbers are the ones with checked checkboxes.

In short, if you use multiple checkboxes, remember to add _any and enter multiple: true.

Next is the 1,'' part. This means that if the checkbox is checked, it will return the data 1, and if the checkbox is not checked, it will return ''. ''? ?? I wonder what it is, but the point is that I will not send any data because the check box was not checked. Isn't it easier to say that it's empty? So, the meaning of this number is the id number this time. This time, I used a gem called ActiveHash to put data like this. ↓↓↓ ファイル名 The number will be the number of this id.

ActiveHash can be easily done by looking at this article. I tried to create prefecture data with Rails gem'active_hash'

To explain again using the data sent by the parameters, ["1", "", "", "", "", ""] Only the new and unused checkboxes with id: 1 are checked, and the remaining 5 are unchecked, so it is''. Therefore, the data that matches the data of new and unused in the status_id column is extracted.

I hope you can understand this somehow.

④ Search for shipping charges will be omitted. ③ Because the search for the status is exactly the same as what you are doing.

Set to controller

First, from the code

item_controller.rb


def index #index is the view of the search form
  @q = Item.ransack(params[:q])
end

def detail_search #detail_search is a view of search results
  @q = Item.ransack(params[:q])
  @items = @q.result(distinct: true)
end

If you receive the parameters received in the search form with params [: q] and set ʻItem.ransack (params [: q]), create an object of the search result based on the received parameters (search data). Can be done. Then, for that object, you can get the search results by setting @items = @ q.result`.

It's hard to understand, but it's okay if you can recognize that you are receiving the input data, creating a search object, and outputting the search results.

And about distinct: true, distinct is a feature in SQL that eliminates duplication. By setting it to true, you can eliminate duplicate contents from the result.

Create a view of search results

After that, you can create a view of the search results (here, the file is detail_search.html.haml) and output it using the each method.

detail_search.html.haml


.contents__box
  - @items.each do |item|
Below this, please make it in light of what you are making now.



Finally

I will also attach SCSS for the time being.

*****.scss


.title-box{
  width: 40%;
  height: 60px;
  border: 1px solid #EEEEEE;
  background-color: red;
  box-shadow: 1px 1px 1px rgba(1,0,0,0.4);
  margin-left: 40%;
  margin-top: 40px;
  padding: 14px 3px 0 0;
  .title{
    color: #fff;
    font-size: 20px;
    font-weight: bold;
    text-align: center;
  }
}

.detail_search--box{
  margin-left: 40%;
  margin-top: 5px;
  width: 40%;
  border: 1px solid #EEEEEE;
  background-color: #fff;
  box-shadow: 1px 1px 1px rgba(1,0,0,0.1);
  .detail-keyword{
    margin-top: 20px;
    &--box{
      display: flex;
      margin-left: 15px;
      .fa-plus{
        margin: 3px 5px 0 0;
      }
    }
    &--form{
      width: 90%;
      height: 40px;
      margin-left: 15px;
      margin-top: 5px;
      padding-left: 5px;
      border: 1px solid #cccccc;
      border-radius: 5px 5px 5px 5px / 5px 5px 5px 5px;
    }
  }
  .detail-price{
    margin-top: 25px;
    &--label{
      display: flex;
      margin-left: 15px;
      .fa-coins{
        margin: 3px 5px 0 0;
      }
    }
    &--forms{
      margin-top: 5px;
      .price-min{
        width: 90%;
        height: 40px;
        margin-left: 15px;
        border: 1px solid #cccccc;
        border-radius: 5px 5px 5px 5px / 5px 5px 5px 5px;
        padding-left: 5px;
      }
      .wd{
        margin-left: 15px;
        color: #AAAAAA;
      }
      .price-max{
        width: 90%;
        height: 40px;
        margin-left: 15px;
        border: 1px solid #cccccc;
        border-radius: 5px 5px 5px 5px / 5px 5px 5px 5px;
        padding-left: 5px;
      }
    }
  }
  .detail-status{
    margin-top: 25px;
    &--label{
      display: flex;
      margin-left: 15px;
      .fa-paperclip{
        margin: 3px 5px 0 0;
      }
    }
    &--checkbox{
      margin-top: 5px;
      .checkboxes{
        margin-left: 15px;
      }
    }
  }
  .detail-deliveryFee{
    margin-top: 25px;
    &--label{
      display: flex;
      margin-left: 15px;
      .fa-truck{
        margin: 3px 5px 0 0;
      }
    }
    &--checkbox{
      margin-top: 5px;
      .checkboxes{
        margin-left: 15px;
      }
    }
  }

  .detail-btn{
    margin-top: 20px;
    .sbt-btn{
      width: 60%;
      height: 35px;
      margin: 15px 0 20px 45px;
      border: none;
      border-radius: 10px;
    }
    .sbt-btn:hover{
      opacity: 0.5 ;
      background-color: #C0C0C0;
    }
  }
}

After that, since we are using icons this time, we also need to install gem'font-awesome-sass'. If you need this, it's easy, so please start from the article below. rails font-awesome-sass installation method

This should look like the image attached earlier above! Please contact us if there are any deficiencies such as failure to implement!

Thank you very much.

Recommended Posts

[Rails] Implementation of search function using gem's ransack
Search function using [rails] ransack
[Rails 6] Implementation of search function
Implementation of search function
Rails search function implementation
[Rails 6] Implementation of inquiry function using Action Mailer
[Rails] Implementation of image enlargement function using lightbox2
Rails fuzzy search function implementation
Implementation of sequential search function
Use ransack Search function implementation
[Rails] Implementation of category function
[Rails] Implementation of tutorial function
[Rails] Implementation of like function
[Rails] Implementation of multi-layer category function using ancestry "Preparation"
[Rails] Implementation of multi-layer category function using ancestry "seed"
[Rails] Implementation of CSV import function
[Rails] Asynchronous implementation of like function
[Rails] Implementation of image preview function
[Rails] About implementation of like function
[Rails] Implementation of user withdrawal function
[Rails] Implementation of CSV export function
[Rails] Set validation for the search function using Rakuten API (from the implementation of Rakuten API)
[Rails] Implementation of multi-layer category function using ancestry "Editing form"
[Rails] Implementation of multi-layer category function using ancestry "Creation form"
[Rails] Implementation of tagging function using intermediate table (without Gem)
Implementation of user authentication function using devise (2)
Implementation of user authentication function using devise (1)
Rails [For beginners] Implementation of comment function
[Rails 6] Implementation of SNS (Twitter) sharing function
Implementation of user authentication function using devise (3)
[Vue.js] Implementation of menu function Implementation version rails6
[Ruby on rails] Implementation of like function
[Vue.js] Implementation of menu function Vue.js introduction rails6
[Rails] Implementation of new registration function in wizard format using devise
[Rails] Implementation of coupon function (with automatic deletion function using batch processing)
[Rails] Implementation of tag function using acts-as-taggable-on and tag input completion function using tag-it
Rails hashtag search implementation
Implementation of Ruby on Rails login function (Session)
[Rails] Implement search function
[Rails] I will explain the implementation procedure of the follow function using form_with.
[Rails] Implementation of retweet function in SNS application
Let's make a search function with Rails (ransack)
[Rails] Implementation of batch processing using whenever (gem)
Implementation of search function Learning memo (portfolio creation)
Implementation of pagination function
[Rails] Implementation of PV number ranking using impressionist
Search function [copype implementation]
[Rails] Implementation of image slide show using Bootstrap 3
[Note] Summary of rails login function using devise ①
Ruby on Rails <2021> Implementation of simple login function (form_with)
[Rails] Implementation of drag and drop function (with effect)
[Rails] Test of star evaluation function using Raty [Rspec]
Implementation of Ruby on Rails login function (devise edition)
[Ruby on Rails] Implementation of tagging function/tag filtering function
[Rails] Implementation of SNS authentication (Twitter, Facebook, Google) function
Rails learning How to implement search function using ActiveModel
Rails implementation of ajax removal
[Rails] Implement User search function
Implementation of like function (Ajax)
Implementation of image preview function
Implementation of category pull-down function