Alex
Alex

Reputation: 203

Rails 4 searchkick with many-to-many relationsip

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

Answers (1)

Pavel Bulanov
Pavel Bulanov

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

Related Questions