Nested model searching Rails + Tire + ElasticSearch, indexing problems

101 views Asked by At

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!

0

There are 0 answers