Mac OS Catalina 10.15.7 ruby 2.6 series rails 6.0 series
As a premise, I will explain using the application that I am currently making that can post articles as an example. I have a model name of post model. (For reference, please replace it for yourself.)
First, set up the routing. This time, it is necessary to define an action other than the basic action (index, new, create, show, edit, update, destroy) called search action, so set it using collection.
routes.rb
Rails.application.routes.draw do
  devise_for :users
  root to: "posts#index"
  resources :posts do
    resources :comments, only: [:create, :destroy]
    collection do
      get 'search'
    end
  end
  resources :users, only: :show
end
The collection allows you to customize the routing URL and the controller to be executed. You can also use member if you want to include the id in the routing.
routes.rb
member do
  get 'search'
end
Simply make the collection a member.
In my example this time, id is not needed, so I am using collection.
Now that we have the routing, let's create a search form to place in the view.
index.html.erb
<%= form_with(url: search_posts_path, local: true, method: :get, class: "search-form") do |form| %>
  <%= form.text_field :keyword, placeholder: "Search for posts", class: "search-input" %>
  <%= form.submit "Search", class: "search-btn" %>
<% end %>
I think there are many ways to write it, but I learned it like this.
The point is that it contains the path (search_posts_path) generated in the routing settings earlier (check the path name on the console), and don't forget method :: get.
In addition, the key name of the text_field of form_with is keyword.
Now, let's write the processing when actually searching in the model. At this time, I understand that I want to write it in the controller, but when defining a method that interacts with the table, try to write it in the model as much as possible. def self.search The following (excluding the end at the bottom) is the content described this time.
post.rb
class Post < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :category
  belongs_to :user
  has_one_attached :image
  has_many :comments, dependent: :destroy
  with_options presence: true do
   validates :image
   validates :title
   validates :category_id, numericality: { other_than: 1 , message: "Is--Please choose from"} 
  end
  def self.search(search)
    if search != ""
      Post.where(['title LIKE(?) OR explanation LIKE(?) OR animal_name LIKE(?)', "%#{search}%", "%#{search}%", "%#{search}%"])
    else
      Post.includes(:user).order('created_at DESC')
    end
  end
end
As a basic writing style
Object name.where('Column name you want to search LIKE(?)', "%#{search}%")
When you want to search in multiple columns
Object name.where(['Column name you want to search LIKE(?) OR Column name you want to search LIKE(?)', "%#{search}%", "%#{search}%"])
You can do it like this. In my case, I want to search in 3 columns, so the description is as above.
Also, if the search field is empty in the if statement, the list of posts is displayed.
Next, write the controller.
posts_controller.rb
def search
  @posts = Post.search(params[:keyword])
end
I am using the search method defined in the model earlier. [: Keyword] in the argument params is the key name of text_field, which was set when the search form was created.
Finally, create the view referenced by the search action. I think that you can jump to the index page with render without making it separately.
search.html.erb
<%= render "shared/header"%>
<%= form_with(url: search_posts_path, local: true, method: :get, class: "search-form") do |form| %>
  <%= form.text_field :keyword, placeholder: "Search for posts", class: "search-input" %>
  <%= form.submit "Search", class: "search-btn" %>
<% end %>
<% if @posts == [] %>
<h2 class = "seach-result">No results</h2>
<% else %>
<div class = "post-contents">
  <ul class = "post-list">
    <% @posts.each do |post| %>
    <li class = "list">
      <%= link_to post_path(post.id) do %>
      <%= image_tag post.image, class: "post-img" %>
      <h3 class='post-title'><%= post.title %></h3>
      <p class = "root-show">~ Click to see details ~</p>
      <% end %>
    </li>
    <% end %>
  </ul>
</div>
<% end %>
<%= link_to new_post_path, class: 'post-btn' do %>
  <span class='post-btn-text'>Post</span>
<% end %>
<%= render  "shared/footer" %>
The above is how to implement the search function in rails. I'm glad if you can use it as a reference.
Recommended Posts