Skip to content

Instantly share code, notes, and snippets.

@tsujigiri
Created May 23, 2011 06:30
Show Gist options
  • Save tsujigiri/986323 to your computer and use it in GitHub Desktop.
Save tsujigiri/986323 to your computer and use it in GitHub Desktop.
mcmire's Geokit branch
class Location < ActiveRecord::Base
has_many :foos
acts_as_mappable default_units: :kms
end
class Foo < ActiveRecord::Base
belongs_to :location
acts_as_mappable through: :location
end
foos = Foo.geo_scope(origin: "berlin")
foos.first.distance
# => NoMethodError: undefined method `distance' for #<Foo:0x00000005ba50b8>
@mcmire
Copy link

mcmire commented May 23, 2011

Well, stupid question first: does your foos table have a distance column?

@mcmire
Copy link

mcmire commented May 23, 2011

Also, you don't have a belongs_to / has_one :location relation in your Foo model. That's probably your problem.

@mcmire
Copy link

mcmire commented May 23, 2011

Also also, you don't have add the .includes([:location]) bit... the geo_scope method should already do that with my branch :)

@tsujigiri
Copy link
Author

Well, the foos don't have a distance column. As I understand it, the distance attribute is added on the fly when geo_scope is called? At least it works that way, when I call it on locations directly. Adding the column doesn't help either, it doesn't get filled.
The associations are there, I just forgot to add them here. Also, it doesn't work without the includes.

I'm using PostgreSQL, could this have something to do with it? Or did I screw up somewhere else?

@tsujigiri
Copy link
Author

Gnaah... I missed the branch. m(. Sorry. With the correct branch it works without the includes, but still no distances. Without the column I get the same error, with the column it is nil. The locations all have latitude and longitude set.

How do I get the database settings in there for the tests?

@mcmire
Copy link

mcmire commented May 24, 2011

How do I get the database settings in there for the tests?

See test/database.yml -- the test_helper loads this. If you look in test/boot.rb there's a constant, ADAPTER, which gets set based on ENV["DB"]. So when running the tests you'll want to pass DB=postgres on the command line.

However, see below...

As I understand it, the distance attribute is added on the fly when geo_scope is called?

Not quite. It's been a while since I've looked at this so I had to take another look at the code. distance isn't an attribute -- I'm not sure what the proper name for it is but it's kind of a virtual column (from the perspective of SQL).

The way the original geokit-rails plugin worked is, if you referred to distance within a regular .find query, when the query was executed, "distance" would literally get replaced with a bunch of SQL which corresponds to the mathematical formula to calculate the distance geographically between two coordinates (specifically, measure the distance between the coordinates of each location in your table).

This is also how it works in the Rails 3 version of geokit-rails, except now that the geokit-rails specific stuff is wrapped in ActiveRecord scopes, it has to work a bit differently. Now when you call .geo_scope, five things happen:

  1. The distance formula SQL is generated and cached.
  2. An instance of a subclass of ActiveRecord::Relation (the subclass is Geokit::ActsAsMappable::Relation) is created.
  3. Certain options passed to .geo_scope (:within, :beyond, :range, bounds) are converted into calls to .where on this new arel instance.
  4. It's in these calls to .where that "distance" is replaced with the distance formula SQL.
  5. The arel instance is returned. This affords you two things:
    1. You can make further calls to .where after the call to .geo_scope which contain "distance", and it will be replaced appropriately.
    2. You can also make a call to .order after the call to .geo_scope (or any method called after .geo_scope) which contains "distance", and it will be replaced appropriately.

So to summarize, geo_scope doesn't add distance to the records that get returned -- it's merely used in your query.

@tsujigiri
Copy link
Author

Thanks for the insights! Got it working now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment