Setting Up an rgeo MySQL Adapter for Your Rails 4 App: Why You Should Use geokit-rails Instead

I had a case where I needed to store coordinates of latitude and longitude and would have to calculate a distance/radius from one point to another. It is an interesting geospatial problem, and one that has been solved before. Somebody recommended the rgeo gem to me. It became apparent very quickly that there is not much documentation to help you get set up with it and MySQL (the database I was using), so even though I ended up using the geokit-rails gem instead, I would still like to share how to get it set up.

I wanted to store a latitude and longitude as a point in my MySQL table. To be able to do that, you need to install the activerecord-mysql2spatial-adapter gem, and what I found was that the last change to it was made years ago. This scared me. If it hasn't scared you away, then you can follow these steps to get all set up with it:

  1. Add the relevant gems to your Gemfile. Note that even though there are later versions out there for rgeo, you'll have to downgrade to be able to use the mysql adapter:

    gem 'activerecord-mysql2spatial-adapter', '~> 0.4.3'
    gem 'rgeo-activerecord', '~> 0.4.6'
    gem 'rgeo', '~> 0.3.20'
    
  2. Change your database adapter in the config/database.yml file from adapter: mysql2 to adapter: mysql2spatial

  3. Change your ActiveRecord schema format to be :sql by putting the following in your config/application.rb:

    config.active_record.schema_format = :sql
    

    This is one of the reasons I was off put by this mysql adapter—by changing your format to sql style, you are making your app more database-dependant. But, you have to do this for your spatial table to be able to use the MyISAM engine, which is what this extension requires.

  4. Create the migration to add your table, with a point and an index for it:

    class CreateLocations < ActiveRecord::Migration
      def change
        create_table :locations, options: "ENGINE=MyISAM" do |t|
          t.column :latlon, :point, null: false
    
          t.timestamps
        end
    
        add_index :locations, :latlon, spatial: true
      end
    end
    

    Note that the point's type is actually column—that's not a typo.

  5. Assuming you're using FactoryGirl for your tests, you'll want to set up a factory for your location model. Here's how you do that with a point data type:

    factory :location do
      point "POINT(48.32414 2.12665)"
    end
    

I decided that the lack of good documentation and support for my needs were not worth it. I found the geokit-rails gem which looks easy to use—and for my purposes, I'm perfectly fine storing a latitude and a longitude field separately as decimals in my MySQL table. The results were great. I won't go into how to install it, since the documentation for this one happens to be very good. But I will point out a nice usage of it—you can use it as part of a scope on your model to filter records by distance:

scope :within_radius_from, -> (radius, latitude, longitude) { within(radius, origin: [latitude, longitude]) }

I'll definitely be recommending geokit in the future. Please feel free to contact me or leave a comment and let me know of even better gems for geospatial calculations.