ホーム > カテゴリ > Ruby・Ruby on Rails >

ransackで親子関係テーブルの検索 [Ruby on Rails]

1つのフォームで「親子関係」がある複数のテーブルを検索する方法です。

モデル(テーブル構成)

例として「掲示板システム」で「questions」(質問テーブル)、「answers」(回答テーブル)をransackで扱う仕様とします。

questions - 質問テーブル

項目名備考
idinteger
titlestringタイトル

answers - 回答テーブル

項目名備考
idinteger
question_idintegerquestionsテーブルのid
namestring名前
urlstringURL
bodystring本文

コントローラー側

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


この記事を書いた人

💻 ITスキル・経験
サーバー構築からWebアプリケーション開発。IoTをはじめとする電子工作、ロボット、人工知能やスマホ/OSアプリまで分野問わず経験。

画像処理/音声処理/アニメーション、3Dゲーム、会計ソフト、PDF作成/編集、逆アセンブラ、EXE/DLLファイルの書き換えなどのアプリを公開。詳しくは自己紹介へ
プチモンテ代表、アーティスト名:プチモンテ
🎵 音楽制作
BGMは楽器(音源)さえあれば、何でも制作可能。歌モノは主にロック、バラード、ポップスを制作。歌詞は叙情詩、叙情的な楽曲が多い。楽曲制作は2023年12月中旬 ~

オリジナル曲を始めました✨

YouTubeで各楽曲を公開しています🌈
https://www.youtube.com/@petitmonte

【男性ボーカル】DA・KA・RA | 新たな明日が風と共に訪れる

【男性、女性ボーカル】時空を超越する先に | 時空と風の交響曲

【女性、男性ボーカル】絆 | 穏やかな心に奏でる旋律