引用
というかこちらを書き直して、自分の経験を元にコメントを記載したものです。
EC-CUBEな日々 RUBY ON RAILSで複数のモデルが絡む検索画面の作り方
実行環境
- Ruby 2.2.2
- Rails 4.2.3
やりたいこと
- views/parents/index に簡単な検索機能を実装する
- 複数の検索条件をandでつなげる
- 関連テーブルについても検索を行う
比較的簡単な実装だと思います。
簡単な検索をつくるだけなら負荷はransackと比べると小さいと思います(負荷に関するテストはしていませんがransack自体が重たくなりがちなので)。
orでつなげる検索はこのやり方では出来ませんが、ransackを利用するととても簡単です。
model
こんな関係を用意します。
親 has_many 子
親も子も名前(:name)を持ちます。
親をつくる.rb
rails generate scaffold parent name:string
子をつくる.rb
rails generate scaffold child name:string parent:references
parent.rb
class Parent < ActiveRecord::Base
has_many :childs
end
child.rb
class Child < ActiveRecord::Base
belongs_to :parent
end
コード
controller
def index
について
@search_form.search
は初期値だとMember(null)
になるので、初期値の場合のみ上書きします。
(もっとうまい書き方があれば教えてください)class ParentSearchForm
について
親に検索に一致する複数の子があった場合、親が複数行表示されてしまうので、子の検索には.uniq
をつけて重複を防ぎます。
(人名だとなかなかありえませんが、例えば「子の年齢がxx歳」や「子の性別がxx」検索する場合は一人の親が検索に一致する複数の子を持つ可能性はあるかと思います)
parents_controller.rb
def index
@search_form = ParentSearchForm.new(params[:search])
@parents = @search_form.search
@parents = Parent.all if @parents == Parent
end
class ParentSearchForm
include ActiveModel::Model
attr_accessor :name, :child_name
def search
rel = Parent
rel = rel.where( name: name ) if name.present?
rel = rel.joins( :child ).where( "childs.name" => child_name ).uniq if child_name.present?
rel
end
end
view
先ほどParentSearchForm
で用意したattributeを設定します
views/parents/index.html.erb
<%= form_for @search_form, as: 'search', url: :parents, html: {method: :get} do |f| %>
<%= f.label :name, "親の名前" %>
<%= f.text_field :name %><br>
<%= f.label :child_name, "子の名前" %>
<%= f.text_field :child_name %>
<%= f.submit "検索" %>
<% end %>
この検索フォームで@parents
に検索結果が返ってくるので<% @parents.each do |parent| %>
あたりを使って一覧を表示してやれば良いです。