I am creating an application that allows you to search and browse articles. This time, I implemented the search function using a gem called'ransack', so I will describe it for memorandum and review.
Ruby on Rails '6.0.0' Ruby '2.6.5'
The article post (article table) has already been created, and the user can view the article.
It is a gem that can implement a simple search form and also create an advanced search form. By introducing this ransack, the following methods can be used.
--_eq method: Search according to the conditions --_cont method: Partial match --_iteq method: Search condition "less than or equal to"
There are various other search methods, but I will omit them this time.
The official GitHub is here.
Gemfile
gem 'ransack'
Terminal
% bundle install
Install the gem with the above command.
config/routes.rb
(Omitted)
get 'articles/search'
This time, we have implemented the article search function, so we will call it "articles controller". The search function is named "search action".
First, I will describe the whole, and then I will explain partly.
app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
before_action :search_article, only: [:index, :search]
def index
@articles = Article.includes(:user).order('created_at DESC').limit(4)
@ranks = Article.find(Like.group(:article_id).order('count(article_id) DESC').limit(4).pluck(:article_id))
end
・ ・ ・(中略)・ ・ ・
def search
@results = @a.result(distinct: true).page(params[:page]).per(8).order('created_at DESC')
end
private
def search_article
@a = Article.ransack(params[:q])
end
end
app/controllers/articles_controller.rb
private
def search_article
@a = Article.ransack(params[:q])
end
In this description, I'm looking for article information from the articles table using the key (: q). And it creates a search object named "@a". The method name that performs this process is "search_article", and since it is used only in the index and search actions, it is limited to "only" in before_action.
app/controllers/articles_controller.rb
def search
@results = @a.result(distinct: true).page(params[:page]).per(8).order('created_at DESC')
end
And, for this @a, by setting ".result", the search result is acquired.
--"Distinct: true": Duplicate data can be excluded and acquired --.page (params [: page]) .per (8) .order ('created_at DESC') ": Use pagination of gem called kaminari so that 8 articles are displayed in the order of creation on one page. I am.
ruby:app/views/layouts/_search.html.erb
<%= search_form_for @a, url: articles_search_path do |f| %>
<div class="search-wrapper">
<div class="search-content col-12">
<%= f.label :type_id_eq, 'Select type', class: 'label' %>
<div class="radio-btn">
<%= f.radio_button :type_id_eq, '', {checked: true} %>unspecified
<%= f.radio_button :type_id_eq, 1 %>Subsidies / subsidies
<%= f.radio_button :type_id_eq, 2 %>Institutional loan
</div>
</div>
<div class="search-content col-12">
<%= f.label :area_id_eq, 'Select a region', class: 'label' %>
<%= f.collection_select(:area_id_eq, Area.all, :id, :name, {include_blank: "---"}, {class:"search-select-box float-right"}) %>
</div>
... (Omitted) ...
<div class="search-content col-12">
<%= f.label :title_or_infomation_cont, 'Keyword search', class: 'label' %>
<%= f.search_field :title_or_information_cont, placeholder: 'Enter a keyword', class:"search-form-control float-right" %>
</div>
<div class="search-content col-12 text-center">
<%= f.submit 'Search by this condition', class:"btn btn-outline-success search-btn" %>
</div>
</div>
<% end %>
I will explain partly.
ruby:app/views/layouts/_search.html.erb
<%= search_form_for @a, url: articles_search_path do |f| %>
This is the first line. A search form is generated by passing "@a (search object)" as an argument of search_form_for.
ruby:app/views/layouts/_search.html.erb
<div class="search-content col-12">
<%= f.label :type_id_eq, 'Select type', class: 'label' %>
<div class="radio-btn">
<%= f.radio_button :type_id_eq, '', {checked: true} %>unspecified
<%= f.radio_button :type_id_eq, 1 %>Subsidies / subsidies
<%= f.radio_button :type_id_eq, 2 %>Institutional loan
</div>
</div>
--type_id_eq will search for the one that matches (= equal) the one selected with the radio button. type_id is included as an article column. --By setting "checked: true", it will be selected by default.
ruby:app/views/layouts/_search.html.erb
<div class="search-content col-12">
<%= f.label :area_id_eq, 'Select a region', class: 'label' %>
<%= f.collection_select(:area_id_eq, Area.all, :id, :name, {include_blank: "---"}, {class:"search-select-box float-right"}) %>
</div>
--area_id_eq is also looking for a match area. -<% = f.collection_select ~%> will generate a pull-down. This time, the article posting function has already created an Area model using ActiveHash.
ruby:app/views/layouts/_search.html.erb
<div class="search-content col-12">
<%= f.label :title_or_infomation_cont, 'Keyword search', class: 'label' %>
<%= f.search_field :title_or_information_cont, placeholder: 'Enter a keyword', class:"search-form-control float-right" %>
</div>
--"Title_or_information_cont": In the column of this article, there is information on title and information, and I am looking for a part of it that matches the keyword (_cont).
ruby:app/views/articles/search.html.erb
<div class="container">
<h5 class="article-title"><i class="fas fa-poll-h fa-2x my-orange"></i>Search result list</h5>
<div class="row">
<% if @results.length !=0 %>
<% @results.each do |result| %>
<div class="card-group col-md-6 col-lg-3">
<%= link_to article_path(result.id), class: "article-link" do%>
<span class="article-info"><%= result.genre.name %></span>
<div class="card articles-chart">
<%= image_tag result.image, class:"card-img-top" if result.image.attached? %>
<div class="card-body">
<h5 class="card-title"><%= result.title %></h5>
<p class="card-text"><%= result.information.truncate(30) %></p>
<p class="like-button"><i class="far fa-heart fa-2x" style="color: #e82a2a;"></i><span style="color: #e82a2a"><%= result.likes.count %></span></p>
</div>
</div>
<% end %>
</div>
<% end %>
<% end %>
<% else %>
<h5 class="alert">There are no applicable posts!</h5>
<% end %>
</div>
</div>
-<% if @ results.length! = 0%>: Conditional bifurcation is performed depending on whether there is a search result, and if there is, the article is displayed, and if not, "There is no corresponding post!" Is displayed.
This completes the implementation.
Since it is a part of the implementation, there may be some expressions that are difficult to understand, Please point out any questions.
Recommended Posts