7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】ActiveHashのデータでプルダウン検索する機能を実装

Last updated at Posted at 2020-12-20

概要

ActiveHashのデータでプルダウン検索する機能を実装する方法について、まとめます。
機能の実装には、ransackというgemを用いました。

ransackは複雑な検索を可能にするgemです。
今回の機能はシンプルな検索なので、ransackを用いなくてもできるかも知れません。
その点については今後の課題とします。

参照



- ransackのGitHubページ
https://github.com/activerecord-hackery/ransack - Ransackで簡単に検索フォームを作る73のレシピ
http://nekorails.hatenablog.com/entry/2017/05/31/173925

完成イメージ

今回は、写真投稿アプリを題材にカテゴリーを選択後、そのカテゴリーの写真一覧を表示する方法を説明します。

Image from Gyazo

開発環境

  • macOS Catalina 10.15.7
  • ruby 2.6.5
  • Rails 6.0.3.4

実装の流れ

  1. gem ransackをインストール
  2. ルーティングを設定
  3. コントローラーにアクションを設定
  4. 検索ボックスを作成
  5. 検索結果ビューを作成

今回のコード

コードは、必要な部分以外(CSSなど)は省略して記載します。
ActiveHashを用いた疑似モデルの作成方法についても省略します。疑似モデルの作成が完了しているという前提で話を進めます。作成方法については参照ページなどをご覧ください。

1. gem ransackをインストール

Gemfile
# ファイルの一番下に追記
gem 'ransack'
ターミナル
% bundle install

2. ルーティングを設定

routes.rb
get '/photo/category', to: "photos#category"

photosコントローラーにcategoryアクションを設定します。
categoryアクションが実行されると、カテゴリー検索結果のページが表示されるようにします。

3. コントローラーにアクションを設定

photos_controller.rb
 before_action :search_category_photo, only: [:index, :category, :hashtag, :search]

 (省略)

  private

  def search_category_photo
    @q = Photo.ransack(params[:q])
  end

privateメソッドにsearch_category_photoメソッドを作成します。これを実行すると、@q = Photo.ransack(params[:q])という検索オブジェクトが作成されます。

今回、検索結果ボックスをヘッダーに格納しました。それにより、カテゴリー検索結果画面(:category)だけでなく、トップ画面(:index)、ハッシュタグ検索結果画面(:hashtag)、キャプション検索結果画面(:search)にも、検索結果ボックスが表示されています。そのため、before_actionで各画面のロード時にsearch_category_photoメソッドが実行されるようにします。これがないとエラーがでました。この解決に苦労しました…。

photos_controller.rb
  def category
    @photos = @q.result
    category_id = params[:q][:category_id_eq]
    @category = Category.find_by(id: category_id)
  end

categoryメソッド内に@photos = @q.resultを記入し、検索結果を取得します。

params[:q]には検索パラメーターが格納されています。

例えば、ActiveHash疑似モデルのid:5のカテゴリーをプルダウンで選択した場合、params[:q]には、以下のものが格納されていました。

console
[1] pry(#<PhotosController>)> params[:q]
=> <ActionController::Parameters {"category_id_eq"=>"5"} permitted: false>

検索結果ビューで選択したカテゴリー名を表示するため、category_id = params[:q]:category_id_eq]として、params[:q]内のcategory_id(この例では"5")を取得しました。そのcategory_idを用いて@category = Category.find_by(id: category_id)として、選択したカテゴリー名を取得しました。

4. 検索ボックスを作成

以下は、今回作成したカテゴリーのActiveHash疑似モデルです。

catetory.rb
class Category < ActiveHash::Base
  self.data = [
    { id: 0, name: '--' },
    { id: 1, name: '犬' },
    { id: 2, name: '猫' },
    { id: 3, name: '鳥' },
    { id: 4, name: '魚' },
    { id: 5, name: '爬虫類' },
    { id: 6, name: '両生類' },
    { id: 7, name: '昆虫' },
    { id: 8, name: 'その他' }
  ]
  include ActiveHash::Associations
  has_many :photos
end
_header.html.erb
<%= search_form_for @q, url: photo_category_path do |f| %>
    <%= f.collection_select :category_id_eq, Category.where.not(id: 0), :id, :name, include_blank: "カテゴリー検索" %>
    <%= f.submit '検索' %>
<% end %>

ransackのヘルパーメソッドsearch_form_forメソッドで、検索フォームを作成します。引数に検索オブジェクト@qを渡しています(参照:『3. コントローラーにアクションを設定』)。urlのパス名はcategoryアクションのパス名です(rails routesで確認しました)。
ヘルパーメソッドcollection_selectメソッドでプルダウンのカテゴリー選択ボックスを作成します。

注).collection_selectメソッドについて理解が不十分の可能性があります。以下、間違いがありましたらご指摘いただきたいです。

<%= f.collection_select ①:category_id_eq, ②Category.where.not(id: 0), ③:id, ④:name, ⑤include_blank: "カテゴリー検索" %>

①カラム名+ransackの検索メソッド

photosテーブルの:category_idで検索するため、カラム名は:category_idとし、選択したカテゴリーと同じidの写真を取得するため、検索メソッドを-eqとしました。-eqは条件に合った検索を行うメソッドです(イコールのイメージ)。

②プルダウンリストで使う配列データ

ActiveHashのCategoryモデルのデータを使用するため、モデル名Categoryを引数としました。.where.not(id: 0)でid: 0は表示せず、かわりに⑤でinclude_blank: "カテゴリー検索"とし、未選択時は"カテゴリー検索"という文字が検索ボックス内に表示されるようにしました。

③検索に使うカラム名

Categoryモデルのidカラムの値を検索に使うため、:idとしました。

④プルダウンメニューに表示されるカラム名

プルダウンメニューには、Categoryモデルの:idではなく:nameの値を表示したいため、:nameとしました。

5. 検索結果ビューを作成

カテゴリー検索結果ページの内容をcategory.html.erbに記載します。

category.html.erb
# 実装に必要な部分のみ記載しています
<h2>カテゴリー <%= @category.name %></h2>
  <ul>
    <% @photos.each do |photo| %>
      <li>
          <%= image_tag photo.image if photo.image.attached? %>
      </li>
    <% end %>
  </ul>
</div>

@category@photosは、上記、photosコントローラーのcategoryメソッドで設定したインスタンス変数です(参照:『3. コントローラーにアクションを設定』)。

@category.nameで、プルダウンリストから選択したカテゴリー名を取得し検索結果ビューに表示させました。

@photosにはプルダウンリストから選択したカテゴリーの写真が格納されているので、.eachメソッドで1枚ずつ取り出しビューに表示させました。

おわりに

.collection_selectメソッドの引数の入力方法が難しく、何度も試行錯誤して正解にたどり着きました。今回の記事が参考になりましたら幸いです。

初学者のため、間違いや改善点などありましたらご指摘お願いいたします。

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?