I have a rails app which has Recipe model with a few many to many associations. I am trying to build an "advanced search" functionality using ElasticSearch + Tire (I know the gem is retired). I have spent the last couple of days researching what I am doing wrong with little luck. Here is my Recipe Model which at this point works for free-text search and filtering on Cuisine (passed as query param as well):
class Recipe < ActiveRecord::Base
include Rails.application.routes.url_helpers
include Tire::Model::Search
include Tire::Model::Callbacks
belongs_to :chef
belongs_to :cuisine
has_many :recipecourses
has_many :courses, through: :recipecourses
has_many :recipeoccasions
has_many :occasions, through: :recipeoccasions
has_many :likes
def thumbs_up_total
self.likes.where(like: true).size
end
def thumbs_down_total
self.likes.where(like: false).size
end
mapping do
indexes :published_at, type: 'date'
indexes :cuisine_id, type: 'integer'
indexes :cuisine_name
indexes :recipe_occasions
end
def self.search(params)
tire.search( page: params[:page], per_page:4 ) do
#query { string params[:query]} if params[:query].present?
query do
boolean do
must { string params[:query]} if params[:query].present?
must {string params[:cuisine_name]} if params[:cuisine_name].present? && !params[:cuisine_name].blank?
end
end
end
end
def to_indexed_json
to_json(methods: [:recipe_occasions,:cuisine_name,:thumbs_up_total, :thumbs_down_total, :chef_name, :chef_avatar, :mychef_path])
end
def recipe_occasions
occasions.collect{|c| c.occasion_name}
end
def cuisine_name
cuisine.cuisine_name
end
def chef_name
chef.chefname
end
def chef_avatar
chef.avatar.url
end
def mychef_path
chef_path(chef)
end
However I want to add checkboxes to filer based on some of the associations. For example in my search form I will have the list of all occasions and based on the selected the search will filter the only recipes for that occasion.
I tried doing this just for testing and it produces 0 results:
def self.search(params)
tire.search( page: params[:page], per_page:4 ) do
query { string params[:query]} if params[:query].present?
filter :terms, :recipe_occasions => ['New Year']
end
end
I also tried filtering for field which is part of the model (cuisine_id) and it works which makes me think my indexing is messed up:
def self.search(params)
tire.search( page: params[:page], per_page:4 ) do
query { string params[:query]} if params[:query].present?
#filter :terms, :recipe_occasions => ['New Year']
filter :terms, :cuisine_id => [6]
end
end
I have read the tire Documentation as well as a several similar questions on stack overflow but I honestly couldn't understand how to do the indexing properly. Another interesting thing I noticed is that the query parameters in my search are being searched across all indexed methods specified in the to_indexed_json - for example if I have parameter in the http request cuisine=Chinese and in my to_indexed_json I have :occasion_names which happens to contain Chinese New Year, the query will return the recipe for Chinese New Year even if the cuisine is not Chinese(I know the example makes no sense but this is how it works).
Going back to the indexing problems I would greatly appreciate if someone can explain how to do my indexing/mapping properly so that I can filer on fields from the associated models.
Thanks!