Techioz Blog

Ruby on Rails 7 での検索機能の構築

概要

私は Ruby on Rails を初めて使用しており、Ruby on Rails アプリケーションに検索機能を構築しています。詳細は以下のとおりです。

従業員の視点

</div></div>
  <div class="col-sm-9">

<div class="form-group">
 <%= form_with url: employees_path, class: "form-control rounded-0", method: :get do |form| %> 
    <label for="exampleInputEmail1">Search Employee</label>
    
      <%= text_field_tag(:employeesearchfield)  %>
       
    <%= form.submit "Search" %>
    <%end%>
  </div>

ルート

Rails.application.routes.draw do
  
  resources :operations
  get 'operations/:preason', to: 'operations#index'
  get 'pages/Administratorhome'
  get 'pages/userhome'
  devise_for :users
  resources :employees do 

    collection do 
    delete 'delete_multiple'
    end 
    collection do
    post 'import' 
    end
    collection do 
    get 'export'
    end
  end

  put "employees/:id", to: 'employees#show'
  

  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
  root to: "pages#Administratorhome"
  # Below route is required for logout functionality.
  devise_scope :user do
    get 'users/sign_out' => "devise/sessions#destroy"
end
  # Defines the root path route ("/")
  # root "articles#index"
end

従業員管理者

def index
   @employees = Employee.search_employee(params[:employeesearchfield])
  end

従業員モデル

def self.search_employee(employeename)
    
    searchvar = employeename 
    
      if searchvar.nil?
        employeelist = Employee.all
      else
        employeelist = Employee.find_by(name: "searchvar")
      end  
      return employeelist
  end

検索フォームを使用して従業員を検索しようとすると、NoMethod エラーが発生します。

エラー:

@employee インスタンス変数が null である理由が理解できません。

byebug gemを試してデータフローを調べてみました。

検索フォームのパラメーター「params[:employeesearchfield]」がこのメソッドに流入していないことがわかりました。

解決策

@employees.each行でnilに対する未定義のメソッド「each」を取得した場合、それは@employees変数がnilを返していることを意味します。

これはモデル内のこの行が原因で発生します

employeelist = Employee.find_by(name: "searchvar")

find_by は最初に見つかったレコードのみを返すか、見つからない場合は nil を返すためです。さらに、クエリは変数 searchvar ではなく文字列 “searchvar” を常に検索するようにハードコードされています。

問題を解決するには、メソッドを次のように変更します。

def self.search_employee(employee_name)
  if employee_name.nil?
    Employee.all
  else
    Employee.where(name: employee_name)
  end  
end

モデル内で次のようなスコープを定義すると、コードをさらに簡素化できることに注意してください。

scope :filter_by_name, ->(name) { where(name: name) if name }

そして、コントローラーで次のようにスコープを使用します。

def index
  @employees = Employee.filter_by_name(params[:employeesearchfield])
end