I recently faced a similar task for my project ( Rails 4.2.4 / Ruby 2.3.1 ).
We have many amenities. I need to get all the estates that include all the selected amenities.
This is how I resolved it with Ransack
In my case, I have a has_many :through relation.
estate.rb
class Estate < ActiveRecord::Base has_many :estate_comforts has_many :comforts, through: :estate_comforts end
comfort.rb
class Comfort < ActiveRecord::Base has_many :estate_comforts has_many :estates, through: :estate_comforts end
estate_comfort.rb
class EstateComfort < ActiveRecord::Base belongs_to :estate belongs_to :comfort end
For complex queries, you need to search through post . To do this, you need to edit routes like this. And add the search action to estates_controlle.rb . Read the Ransack wiki for more information.
routes.rb
... resources :estates collection do match 'search' => 'estates#search', via: %i[get post], as: :search end end
estates_controller.rb
class EstatesController < ApplicationController ... def index @q = Estate.ransack(params[:q]) @estates = if params[:q]&.has_key?(:estate_comforts_comfort_id_eq_any) # Store checked comforts session[:estate_comforts_comfort_id_eq_any] = params[:q][:estate_comforts_comfort_id_eq_any] comforts_count = params[:q][:estate_comforts_comfort_id_eq_any].count ids = @q.result.includes(:estate_comforts).group_by(&:id).select { |_, v| v.count == comforts_count}.keys Estate.where(id: ids) else @q.result(distinct: true) end end def search index render :index end end
And finally, part of the template ...
Estates / index.haml
= search_form_for @q, url: search_estates_path, html: { method: :post } do |f| # here goes the form inputs # Polulate checkboxes with previously checked comforts - Comfort.find_each do |comfort| # Was checked previously? - checked = comfort.id.to_s.in?(session[:estate_comforts_comfort_id_eq_any].to_a) %div %input{ name: 'q[estate_comforts_comfort_id_eq_any][]', type: "checkbox", id: "checkbox#{comfort.id}", value: comfort.id, checked: checked } %label{for: "checkbox#{comfort.id}"}= comfort.name
Will generate the following html
<form class="estate_search" id="estate_search" action="/estates/search" accept-charset="UTF-8" method="post"> <div> <input checked="" id="checkbox1" name="q[estate_comforts_comfort_id_eq_any][]" type="checkbox" value="1"> <label for="checkbox1">Comfort Name 1</label> </div> <div> <input id="checkbox2" name="q[estate_comforts_comfort_id_eq_any][]" type="checkbox" value="2"> <label for="checkbox2">Comfort Name 2</label> </div> </form>