Railsで絞り込み検索機能を作ってみたい、そんなときはransackというgemを使うことをおすすめします!
今回は登録した車の情報を、ransackを使って検索できるアプリを作成していきます。
完成形はこちらになります!(viewは整えていません)
アプリのバージョンは、
- Ruby 2.6.5
- Rails 6.0.3
それでは早速解説していきます!
アプリの作成
rails newコマンドを使用してアプリを作成していきます!
下記コマンドを参考にしてください。
rails _6.0.0_ new アプリ名 -d mysql
今回データベースは、mysqlを使用しています。
完了したらアプリケーションのディレクトリに移動しておきましょう。
cd 作成したアプリケーション
データベースの作成
下記のコマンドを実行してデータベースを作成しましょう。
rails db:create
次にテーブルの作成をしていきます。
rails g model car
車の検索機能を実装していくので、model名はcarにしています。
マイグレーションファイルを以下のように記述します。
class CreateCars < ActiveRecord::Migration[6.0]
class CreateCars < ActiveRecord::Migration[6.0]
def change
create_table :cars do |t|
t.string :name, null: false
t.integer :price, null: false
t.integer :manufacturer_id, null: false
t.string :grade, null: false
t.integer :body_id, null: false
t.integer :displacement, null: false
t.string :color, null: false
t.integer :capacity, null: false
t.integer :model_year, null: false
t.integer :vehicle_type_id, null: false
t.integer :mileage, null: false
t.timestamps
end
end
end
カラムの内容としては、以下のとおりです。
必要に応じてカラムは調節してください。
ActiveHashも使用していきます。
- 車両名
- 金額
- メーカー(ActiveHash)
- グレード
- ボディ形状(ActiveHash)
- 排気量
- 色 ← ActiveHash使っても良かったかも
- 定員
- 年式
- 車両種別(ActiveHash)
- 走行距離
記述することができたら、テーブルを作成していきます。
問題なく作成できているか確認もしておきましょう。
rails db:migrate
rails db:migrate:status
コントローラーの作成
下記のコマンドを実行して、コントローラーの作成を行います。
同時にviewファイルも作成しておきます。
rails g controller cars index new search
コントローラーは以下のようになっていればOKです。
class CarsController < ApplicationController
def index
end
def new
end
def search
end
end
ルーティングの設定
routes.rbを以下のように記述していきます。
Rails.application.routes.draw do
root "cars#index"
resources :cars, only: [:index, :new, :create] do
collection do
get "search"
end
end
end
createアクションも使用しますので、先にルーティングを設定しています。
gemのインストール
今回インストールするgemは、2つになります。
Gemfileに以下を記述しましょう。
gem "ransack"
gem "active_hash"
記述ができたら
bundle install
を実行しておきましょう。
車両情報の保存機能作成
まずは車両情報を保存するための機能を作成していきます。
今回は検索機能がメインになるので、こちら解説はしません。
以下のコードを確認してください。
views/cars/index.html.erb
<%= link_to "車両登録", new_car_path %>
views/cars/new.html.erb
<%= form_with model: @car, local: true do |f| %>
<p>車両名</p>
<%= f.text_field :name %>
<p>価格</p>
<%= f.text_field :price %>
<p>メーカー</p>
<%= f.collection_select(:manufacturer_id, Manufacturer.all, :id, :name, {include_blank: "---"}) %>
<p>グレード</p>
<%= f.text_field :grade %>
<p>ボディ形状</p>
<%= f.collection_select(:body_id, Body.all, :id, :name, {include_blank: "---"}) %>
<p>排気量</p>
<%= f.text_field :displacement %>
<p>色</p>
<%= f.text_field :color %>
<p>定員</p>
<%= f.text_field :capacity %>
<p>年式</p>
<%= f.text_field :model_year %>
<p>車両種別</p>
<%= f.collection_select(:vehicle_type_id, VehicleType.all, :id, :name, {include_blank: "---"}) %>
<p>走行距離</p>
<%= f.text_field :mileage %>
<%= f.submit "登録する"%>
<% end %>
models/car.rb
class Car < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :manufacturer
belongs_to :body
belongs_to :vehicle_type
with_options presence: true do
validates :name
validates :price
validates :grade
validates :displacement
validates :color
validates :capacity
validates :model_year
validates :mileage
end
end
models/manufacturer.rb
class Manufacturer < ActiveHash::Base
self.data = [
{ id: 1, name: 'トヨタ' },
{ id: 2, name: '日産' },
{ id: 3, name: '三菱' },
{ id: 4, name: 'マツダ' },
{ id: 5, name: 'ホンダ' },
{ id: 6, name: 'スバル' },
{ id: 7, name: 'ダイハツ' },
{ id: 8, name: 'スズキ' },
{ id: 9, name: '外国車' },
{ id: 10, name: 'その他' }
]
include ActiveHash::Associations
has_many :cars
end
models/body.rb
class Body < ActiveHash::Base
self.data = [
{ id: 1, name: 'セダン' },
{ id: 2, name: 'ミニバン' },
{ id: 3, name: 'SUV' },
{ id: 4, name: 'ハッチバック' },
{ id: 5, name: 'クーペ' },
{ id: 6, name: 'オープン' },
{ id: 7, name: '軽自動車' },
{ id: 8, name: 'その他' }
]
include ActiveHash::Associations
has_many :cars
end
models/vehicle_type.rb
class VehicleType < ActiveHash::Base
self.data = [
{ id: 1, name: '新車' },
{ id: 2, name: '未使用車' },
{ id: 3, name: '中古車' }
]
include ActiveHash::Associations
has_many :cars
end
controllers/cars_controller.rb
class CarsController < ApplicationController
def index
end
def new
@car = Car.new
end
def create
@car = Car.new(car_params)
if @car.save
return redirect_to root_path
end
render :new
end
private
def car_params
params.require(:car).permit(:name,
:price,
:manufacturer_id,
:grade,
:body_id,
:displacement,
:color,
:capacity,
:model_year,
:vehicle_type_id,
:mileage)
end
end
rails s
でサーバーを立ち上げて、車両の登録をしておきましょう。
毎回入力するのは面倒だと感じるのであれば、seedファイルを用意しましょう。
ファイルに記述をしたあと、
rails db:seed
を実行し、データベース内に車両の情報を保存していきます。
seedファイルについては、こちらを参考にしてください。
データが保存できたら、次に検索機能の実装をしていきます。
検索機能の実装
ここからは、ransackを使用して検索機能の実装を行っていきます。
ルーティングは、準備段階で記述していますので割愛します。
コントローラーの記述をしていきましょう。
controllers/cars_controller.rb
class CarsController < ApplicationController
before_action :search_car, only: [:index, :search] # 追加
def index
end
def new
@car = Car.new
end
def create
@car = Car.new(car_params)
if @car.save
return redirect_to root_path
end
render :new
end
def search # 追加
@searches = @q.result
end
private
def car_params
params.require(:car).permit(:name,
:price,
:manufacturer_id,
:grade,
:body_id,
:displacement,
:color,
:capacity,
:model_year,
:vehicle_type_id,
:mileage)
end
def search_car # 追加
@q = Car.ransack(params[:q])
end
end
コントローラーで必要になるのは、2つの記述になります。
@q = Car.ransack(params[:q]) # ①
@searches = @q.result # ②
①では、viewで入力した内容(params[:q]内に格納された情報)がテーブルに存在しているか確認しています。
②では、①で取得したデータをActiveRecord_Relationのオブジェクトに変換しています。
この2つを記述があれば、検索機能ができてしまいます。
めちゃめちゃシンプル!
続いてviewを記述していきましょう。
views/cars/index.html.erb
<%= search_form_for @q, url: search_cars_path do |f| %>
<%= f.label :manufacturer_id_eq, 'メーカー' %>
<%= f.collection_select :manufacturer_id_eq, Manufacturer.all, :id, :name, {include_blank: "すべてのメーカー"}, {id: "car-select"} %>
<%= f.collection_select :name_eq, [], :name, :name, {include_blank: "すべての車種"}, {id: "car-name"} %>
<%= f.label :price_gteq, '価格'%>
<%= f.collection_select :price_gteq, Price.all, :price, :name, {include_blank: "下限なし"}%>
~
<%= f.collection_select :price_lteq, Price.all, :price, :name, {include_blank: "上限なし"}%>
<%= f.label :model_year_gteq, '年式'%>
<%= f.text_field :model_year_gteq, placeholder: "下限なし" %>
~
<%= f.text_field :model_year_lteq, placeholder: "上限なし" %>
<%= f.label :mileage_gteq, '走行距離'%>
<%= f.collection_select :mileage_gteq, Mileage.all, :mileage, :name, {include_blank: "下限なし"}%>
~
<%= f.collection_select :mileage_lteq, Mileage.all, :mileage, :name, {include_blank: "上限なし"}%>
<%= f.label :color_in, 'カラー'%>
<%= f.collection_check_boxes :color_in, Color.all, :color, :name, {}%>
<%= f.submit '検索' %>
<% end %>
ransackでは、search_form_forというヘルパーを使用します。
viewの内容については細かく解説はしません。
price
mileage
color
上記の3つのカラムに関しては検索用にActiveHashを作成し使用していますが、プルダウン表示する必要がなければそこまでする必要はありません。
ransackには、eq、cont、gteq、lteqなど複数のオプションが存在しています。
詳しくはこちらが参考になりますので、確認していただければと思います。
最後に検索結果を表示させるためのviewを作成しましょう。
views/cars/search.html.erb
<% if @searches.present? %>
<div class="search-hit">
<%= "#{@searches.length}件見つかりました。" %>
</div>
<% @searches.each do |car| %>
<div class="search-view">
<div class="test">
<%= car.name %>
<%= car.price %>万円
<%= car.manufacturer.name %>
<%= car.grade %>
<%= car.body.name %>
<%= car.displacement %>cc
<%= car.color %>
<%= car.capacity %>人乗り
<%= car.model_year %>年式
<%= car.vehicle_type.name %>
<%= car.mileage %>km
</div>
</div>
<% end %>
<% else %>
<div class="search-hit not-hit">検索結果が見つかりませんでした</div>
<% end %>
<%= link_to "トップページに戻る", root_path %>
ここまでできたら、サーバーを起動して
rails s
検索結果が表示されるか確認してみましょう。
問題なく表示されていたらOKです!
まとめ
今回はransackを使って、絞り込み検索機能を実装していきました。
導入手順を記述しておきます。
- gem ‘ransack’をインストール
- ルーティングの設定
- コントローラーに検索に必要な記述をする
- search_form_forを使って検索欄の作成をする
- 検索結果を表示するためのviewを用意して記述する
Railsで作成したアプリに絞り込み検索機能を実装する場合は、ぜひ活用していきましょう。
最後までご覧頂きありがとうございました。