ransackで親子関係テーブルの検索 [Ruby on Rails]
1つのフォームで「親子関係」がある複数のテーブルを検索する方法です。
モデル(テーブル構成)
例として「掲示板システム」で「questions」(質問テーブル)、「answers」(回答テーブル)をransackで扱う仕様とします。
questions - 質問テーブル
項目名 | 型 | 備考 |
---|---|---|
id | integer | |
title | string | タイトル |
answers - 回答テーブル
項目名 | 型 | 備考 |
---|---|---|
id | integer | |
question_id | integer | questionsテーブルのid |
name | string | 名前 |
url | string | URL |
body | string | 本文 |
コントローラー側
def index @q = Question.all.ransack(params[:q]) @questions = @q.result end
@qは検索パラメータ、@questionsは検索結果です。
ビュー側
SlimとBootstrap4を使用しています。※erbの方は後述するHTMLを参考。
= search_form_for @q, class: 'mb-5' do |f| .form-group.row = f.label :title_cont, 'タイトル', class: 'col-sm-2 col-form-label' .col-sm-10 = f.search_field :title_cont, class: 'form-control' .form-group.row = f.label :answers_body_cont, '本文', class: 'col-sm-2 col-form-label' .col-sm-10 = f.search_field :answers_body_cont, class: 'form-control' .form-group = f.submit class: 'btn btn-outline-primary'
[出力されるHTML]
<form class="mb-5" id="question_search" action="/questions" accept-charset="UTF-8" method="get"> <div class="form-group row"> <label class="col-sm-2 col-form-label" for="q_title_cont">タイトル</label> <div class="col-sm-10"> <input class="form-control" type="search" name="q[title_cont]" id="q_title_cont" /> </div> </div> <div class="form-group row"> <label class="col-sm-2 col-form-label" for="q_answers_body_cont">本文</label> <div class="col-sm-10"> <input class="form-control" type="search" name="q[answers_body_cont]" id="q_answers_body_cont" /> </div> </div> <div class="form-group"> <input type="submit" name="commit" value="検索" class="btn btn-outline-primary" data-disable-with="検索" /> </div> </form>
モデル側
[question.rb]
class Question < ApplicationRecord # 複数のAnswerを子に持つ has_many :answers # 検索対象のカラム ※デフォルトは全て def self.ransackable_attributes(auth_object = nil) %w[title] end end
[answer.rb]
class Answer < ApplicationRecord # Questionに属する belongs_to :question # 検索対象のカラム ※デフォルトは全て def self.ransackable_attributes(auth_object = nil) %w[body] end end
必ず、「ransackable_attributes」で検索対象のカラム(項目)を指定します。デフォルトだと全てのカラムが対象になり、不正に検索される可能性がありますのでご注意ください。
(おまけ)複数キーワードによるAND検索の実装
タイトル(title)を例にすると次のような変数になります。
通常検索(1つ) | title_cont |
---|---|
OR検索(複数) | title_cont_any |
AND検索(複数) | title_cont_all |
def index # スペース区切りを配列に変換して返す。 if params[:q].present? params[:q]['title_cont_all'] = params[:q]['title_cont_all'].split(/[\p{blank}\s]+/) end @q = Question.all.ransack(params[:q]) @questions = @q.result end
スポンサーリンク
関連記事
公開日:2019年10月19日 最終更新日:2020年08月26日
記事NO:02795