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 
プチモンテ ※この記事を書いた人
|  | |
|  | 💻 ITスキル・経験 サーバー構築からWebアプリケーション開発。IoTをはじめとする電子工作、ロボット、人工知能やスマホ/OSアプリまで分野問わず経験。 画像処理/音声処理/アニメーション、3Dゲーム、会計ソフト、PDF作成/編集、逆アセンブラ、EXE/DLLファイルの書き換えなどのアプリを公開。詳しくは自己紹介へ | 
| 🎵 音楽制作 BGMは楽器(音源)さえあれば、何でも制作可能。歌モノは主にロック、バラード、ポップスを制作。歌詞は抒情詩、抒情的な楽曲が多い。楽曲制作は🔰2023年12月中旬 ~ | |

 
        



 
  
 


