0

In my case I have a model Product has_one Location

I use a geocoder gem to search location near a distance.

The request Location.near([0, 0], 100) is look like this:

SELECT locations.*, 6371.0 * 2 * ASIN(SQRT(POWER(SIN((0 - locations.latitude) * PI() / 180 / 2), 2) + COS(0 * PI() / 180) * COS(locations.latitude * PI() / 180) * POWER(SIN((1 - locations.longitude) * PI() / 180 / 2), 2) )) AS distance, CAST(DEGREES(ATAN2( RADIANS(longitude - 1), RADIANS(latitude - 0))) + 360 AS decimal) % 360 AS bearing FROM \"locations\" WHERE (6371.0 * 2 * ASIN(SQRT(POWER(SIN((0 - locations.latitude) * PI() / 180 / 2), 2) + COS(0 * PI() / 180) * COS(locations.latitude * PI() / 180) * POWER(SIN((1 - locations.longitude) * PI() / 180 / 2), 2) )) <= 20) ORDER BY distance

I want to do something like this:

Product.where(...).joins(:location).dosomething

How can I do it?

Ian Bernatcki
  • 108
  • 1
  • 10

2 Answers2

0

Location#near is a named scope? If so you can merge it with your Product scope using the & operator. I think this should work:

class Product
  scope :near, lambda { |coord, dist| joins(:location) & Location.near(coord, dist) }

  ...
end

Then you can just use it like so:

Product.near([0, 0], 100)
tsherif
  • 11,502
  • 4
  • 29
  • 27
  • Yes, it is a scope. I tried it and have got a 3 queries: Proposal Load (5442.1ms) SELECT "proposals".* FROM "proposals" INNER JOIN "locations" ON "locations"."locationable_id" = "proposals"."id" AND "locations"."locationable_type" = 'Proposal' Location Load (186.6ms) SELECT locations.*, 6371.0 * 2 * ASIN(SQRT(POWER(SIN((0 - locations.latitude) ... Proposal Load (4920.5ms) SELECT "proposals".* FROM "proposals" – Ian Bernatcki Apr 13 '12 at 11:24
  • What is Proposal? And can you show the code for `Location#near`? – tsherif Apr 13 '12 at 11:27
  • Proposal == Product. Location#near => https://github.com/alexreisner/geocoder/blob/master/lib/geocoder/stores/active_record.rb#L34 – Ian Bernatcki Apr 13 '12 at 12:36
  • Merging the scopes doesn't seem to work. It might have to do with `select` in the `near` scope. See my other answer. – tsherif Apr 13 '12 at 13:06
0

Another possibility, since merging the scopes doesn't seem to work:

class Product
  scope :near, lambda { |coord, dist| where(:id => Location.near(coord, dist).all.map(&:locationable_id) }

  ...
end

And usage like in the other answer:

Product.near([0, 0], 100)
tsherif
  • 11,502
  • 4
  • 29
  • 27