Search code examples
ruby-on-railselasticsearchtire

Rails model scope based on associated model


I have two relevant models here: InventoryItem and Store.

class InventoryItem < ActiveRecord::Base
  belongs_to    :store
  include Tire::Model::Search
  include Tire::Model::Callbacks

  def self.search(params)
    tire.search(load: true, :per_page => 40) do
      query { string params[:query], default_operator: "AND" } if params[:query].present?
    end
  end
end


class Store < ActiveRecord::Base
  geocoded_by :address
  after_validation :geocode, :if => lambda{ |obj| obj.address_changed? }

  has_many  :inventory_items
end

I want to search inventory_items from stores that are nearby the current user (User is also geocoded using geocoder gem). The approach I'm considering is to scope the model somehow, but I'm unsure of how to implement. Here's how I find nearby stores in my controllers typically:

@stores = Store.near([current_user.latitude, current_user.longitude], current_user.distance_preference, :order => :distance)

Is there a way to do a :local scope on my InventoryItem model somehow based on whether its associated store is nearby the current user? Alternatively, is there a way to accomplish my goal with elasticsearch? Thanks in advance!


Solution

  • There are a few ways you could accomplish this. I think the easiest way to start would be something like this:

    class Store < ActiveRecord::Base
       scope :for_user, -> {|user| near([user.latitude, user.longitude], user.distance_preference, :order => :distance)}
    end
    

    Which would allow you to call

    Store.for_user(whatever_user)
    

    On the Inventory, I would also try to find by stores:

    class InventoryItem < ActiveRecord::Base
      scope :for_stores, -> {|stores| where(store_id: stores.map(&:id))}
    end
    

    I am not familiar with your search engine there, but if it does active record scope nesting, you should be able to do something like:

    InventoryItem.for_stores(Store.for_user(whatever_user)).search(...)