Reputation: 203
How to implement a Category filter for searchkick. Basically I have an input field that takes the query term, but I also want a dropdown that users can pick a category to search from or search in ALL categories. There is a many-to-many relationship between posts and categories
My models are:
-- post.rb
class Post < ActiveRecord::Base
has_many :post_categories
has_many :categories, through: :post_categories
searchkick text_start: [:title]
end
-- category.rb
class Category < ActiveRecord::Base
has_many :post_categories
has_many :posts, through: :post_categories
end
--post_category.rb
class PostCategory < ActiveRecord::Base
belongs_to :post
belongs_to :category
end
Now in my posts_controller index action, I have the following, which works so far by returning all posts that match the query parameter, or returns all posts if no query parameter is provided in the search input.
class PostsController < ApplicationController
def index
query = params[:q].presence || "*"
@posts = Post.search (query)
end
end
This works well so far. But I also want to add a category filter in the view, so that the user can choose to search for the query string within a particular category, or search in all categories if no category is selected. Thanks in advance.
Upvotes: 2
Views: 1064
Reputation: 953
As per searchkick documentation, you can add parameters to .search query - see here section Queries, specifically where. Sample from docs:
Product.search "apples", where: {in_stock: true}, limit: 10, offset: 50
Should be smt like
Post.search query, where: {category: [some_array]}
Note - searchkick gem converts conditions from where statement to ElasticSearch filters (see here)
Update - for searching by attributes of related objects (not model itself), you should include its fields into search_index - see sample here
Add the category titles to the search_data method.
class Project < ActiveRecord::Base
def search_data
attributes.merge(
categories_title: categories.map(&:title)
)
end
end
Also this question on related topic
By default search_data of searchkick is return of serializable_hash model call -see sources for reference.
def search_data
respond_to?(:to_hash) ? to_hash : serializable_hash
end unless method_defined?(:search_data)
Which does not include anything of associations by default, unless passed with :include parameter - source
def serializable_hash(options = nil)
...
serializable_add_includes(options) do ..
end
def serializable_add_includes(options = {}) #:nodoc:
return unless includes = options[:include]
...
end
Upvotes: 2