简体   繁体   中英

Rails sort child model based on parent model distance calculation

I have a product model and a shop model. The relationship between two is shop has_many products and products belongs_to shop.

The shop model has two fields longitude and latitude used for distance calculation using geokit-rails . I have been successful in sorting shops by nearest distance to any given longitude and latitude using:

Shop.by_distance(origin:[params[:latitude], params[:longitude]]).sort_by{|s| s.distance_to([params[:latitude], params[:longitude]])}

The problem is with products. The products needs to be sorted according to nearest shop location as well. I have searched through and found out that a child model can be sorted from parents attributes like this:

Product.joins(:shop).order('shops.name')

The order function works only if supplied with model field. How can I sort products calculating shop distance.

Please help.

Have a look at the documentation on using :through - this should be exactly what you need.

So Product would look like:

class Product < ActiveRecord::Base
  belongs_to :shop
  acts_as_mappable through: :shop
  ...
end

And your query would be something like:

Product.joins(:shop).by_distance(origin: [params[:latitude], params[:longitude]])

If you already can filter and sort the Shop

@shops = Shop.by_distance(origin:[params[:latitude], params[:longitude]]).sort_by{|s| s.distance_to([params[:latitude], params[:longitude]])}

This will get all products from each shops according to the distance:

@closest_products = @shops.map(&:products)

If you want to weed out duplicate products, use this instead:

@closest_products = @shops.map(&:children).flatten.uniq

You may try an alternative method (I have not tested this):

@closest_products = Product.where(shop: @shops)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM