Rails: Get Posts of Users within 10km of a point

363 Views Asked by At

I'm using the rails 3 geokit gem that allows you to find users within a distance of a point, e.g.

User.within(10, origin: [51.123123, 0.1323123])

['10' is the distance in mi/km; 51 & 0 are latitude and longitude]

I'm now trying to get all posts by users who are within a certain distance of a point. something like:

Post.where(User.within(10, origin: [51.123123, 0.1323123]))

(my Post model belongs_to my User model, my User model has_many posts)

Reading around it seems like the solution lies in .where, or using :through & :source, or .joins, but I haven't been able to nail it down.

I'd be very grateful for any help!

4

There are 4 best solutions below

0
On BEST ANSWER

Try this solution:

class Post
  acts_as_mappable through: :user
end

Post.joins(:user).within(10, origin: [51.123123, 0.1323123])
6
On
Post.joins(:user).merge(User.within(10, origin: [51.123123, 0.1323123]))
3
On

There may be a more elegant solution, but I think the simplest may be to use IN with SQL. Do something like:

Post.where(["user_id IN (?)", User.within(10, origin: [51.123123, 0.1323123]).map { |u| u.id }])

Basically, you're just sending an array of user_ids that Post.user_id could match.

6
On

If your User model has_many posts, why don't you just load them directly?

@posts = User.within(10, origin: [51.123123, 0.1323123]).collect(&:posts).flatten

collect is a synonym for map, it effectively transforms an array into another array applying a transforming method or a block to every element of the original array.

In our command above, within is a named scope that returns an array of Users, collect applys the method posts to each user, thereby generating an array of posts per user. Finally, flatten takes the array of posts arrays (its a 2 dimensional array) and squishes it into one big array of posts.

You could also have a default includes in your User model to prevent the N+1 query problem. while loading Posts.

FWIW, I prefer using ActiveRecord methods (associations, etc.) instead of using raw SQL where possible.