views:

174

answers:

2
+2  Q: 

Geokit and rails 3

Hi,

I am using the geokit gem and plugin with rails 3. It seems there is a known issue with them, which can be seen here http://github.com/andre/geokit-rails/issues#issue/15

Now, I tried to follow the solution provided at the bottom. I pasted that function definition, at the end of the file, just above acts_as_mapable, and just after the first time it was called, but nothing happened each time.

Any idea what else can be done?

Thanks

A: 

Hey Amit, Not sure if you sorted this out yet but I'll tell you what I did just in case.

I forked andre's geokit-rails source and then cloned it locally and added the code from this gist at line 34 of lib/geokit-rails/acts-as-mappable.rb, just after the line that reads module ClassMethods # :nodoc:.

Then I commited those changes back to my forked repo on github and used my fork to install the source as a plugin to my rails 3 app. That seemed to work straight away, but make sure you have the acts_as_mappable line added to whatever model you are wanting to do distance calculations on and make sure you have two float columns on that db named :lat and :lng.

erskingardner
hey! yeah that worked, but for some reason the plugin is not working with rails 3 nemore... so i just made my own plugin ;)
Amit
+1  A: 

I ran into similar problems upgrading my app to rails 3. I'm still using Geokit for geocoding but Active Record scopes for distance based database queries. It's pretty convenient, and you still get all of the Active Record 3 goodness. Here's an example from my User model:

scope :near, lambda{ |*args|
                  origin = *args.first[:origin]
                  if (origin).is_a?(Array)
                    origin_lat, origin_lng = origin
                  else
                    origin_lat, origin_lng = origin.lat, origin.lng
                  end
                  origin_lat, origin_lng = deg2rad(origin_lat), deg2rad(origin_lng)
                  within = *args.first[:within]
                  { 
                    :conditions => %(
                      (ACOS(COS(#{origin_lat})*COS(#{origin_lng})*COS(RADIANS(users.lat))*COS(RADIANS(users.lng))+
                      COS(#{origin_lat})*SIN(#{origin_lng})*COS(RADIANS(users.lat))*SIN(RADIANS(users.lng))+
                      SIN(#{origin_lat})*SIN(RADIANS(users.lat)))*3963) <= #{within}
                    ),
                    :select => %( users.*,
                      (ACOS(COS(#{origin_lat})*COS(#{origin_lng})*COS(RADIANS(users.lat))*COS(RADIANS(users.lng))+
                      COS(#{origin_lat})*SIN(#{origin_lng})*COS(RADIANS(users.lat))*SIN(RADIANS(users.lng))+
                      SIN(#{origin_lat})*SIN(RADIANS(users.lat)))*3963) AS distance
                    )
                  }
                }

Here's a blog post with a little more detail on the subject: http://stcorbett.com/code/distance-queries-with-rails-3-without-geokit/

stcorbett
Helpful blog post stcorbett. Getting distance back from the db is handy, and chainable scopes are nice. I'd caution that the new field will appear on the User model (in this case) and you may want to name the field to indicate that its not a permananent attribute of the user, but the distance from another user..
Dean Radcliffe
Ahh, interesting point. I could see going as far as naming the new attribute based on which user the query is calculating distance to. eg: "distance_to_user_#{origin.id}". That gives you an extra hoop to jump through when you want to use the distance data. Good stuff.
stcorbett