Geolocal

Allows IP addresses to geocoded with a single Ruby if statement. No network access, no context switches, no delay. Just one low-calorie local lookup.

Installation

The usual method, add this line to your Gemfile:

gem 'geolocal'

Usage

First create a config file that describes the ranges you're interested in. Here's an example:

Geolocal.configure do
  config.countries = {
    us: 'US',
    central_america: %w[ BZ CR SV GT HN NI PA ]
  }
end

Now run rake geolocal:update. It will download the geocoding data from the default provider (see the providers section) and create lib/geolocal.rb.

Geolocal.in_us?(request.remote_ip)
Geolocal.in_central_america?(IPAddr.new('200.16.66.0'))

You can pass:

  • a string: Geolocal.in_us?("10.1.2.3")
  • an IPAddr object: Geolocal.in_eu?(IPAddr.new('2.16.54.0'))
  • an integer/family combo: Geolocal.in_us?(167838211, Socket::AF_INET)

Config

Here are the supported configuration options:

  • provider: Where to download the geocoding data. Default: DB_IP.
  • module: The name of the module to receive the in_* methods. Default: 'Geolocal'.
  • file: Path to the file to contain the generated code. Default: lib/#{module}.rb.
  • tmpdir: the directory to contain intermediate files. They will require tens of megabytes for countries, hundreds for cities). Default: ./tmp/geolocal
  • countries: the ISO-codes of the countries to include in the lookup.
  • ipv6: whether the ranges should support ipv6 addresses.

Examples

This uses the Countries gem to discover if an address is in the European Union:

require 'countries'

eu_codes = Country.find_all_by_eu_member(true).map(&:first)

Geolocal.configure do |config|
  config.countries = { us: 'US', eu: eu_codes }
end

Now you can call Geolocal.in_eu?(ip). If the European Union membership ever changes, run bundle update countries and then rake geolocal to bring your app up to date.

Providers

This gem currently only supoports the DB-IP database. There are lots of other databases available and this gem is organized to support them. Patches welcome.

Alternatives

The Geocoder gem offers local database services. Geolocal is simpler, faster, and production ready, but the Geocoder gem offers more options and more providers. Geolocal also doesn't add any dependencies to your deploy, potentially making it easier to get working with oddball environments like Heroku.

TODO

  • [ ] include a Rails generator for the config file?
  • [ ] performance information? benchmarks. space saving by going ipv4-only?
  • [ ] Add support for cities
  • [ ] other sources for this data? MainFacts, NirSoft Also maybe allow providers to accept their own options?
  • [ ] Add support for for-pay features like lat/lon and timezones?

Contributing

To make this gem less imperfect, please submit your issues and patches on GitHub.