Finding Visitor Locations in Rails
I've got an application that I work on where the client wants to track which countries they're seeing click-throughs from. They want this in real time and in the application's UI, not in an external package such as Google Analytics. There are various ways to guess at country, but for the purposes of this application, basing it on the IP address and where its range is assigned proves to be good enough.
There are various services that will let you geolocate based on IP just by making an API call. But there's no particular reason to go outside your own application for this; it's pretty trivial to set up in Rails:
1) Download the "Complete (Country) One Table" SQL file from IPInfoDB. This is the raw data necessary to do the lookups. Decompress it and then run the resulting SQL file in your application's database. This will give you an
2) In this particular application, we're maintaining an Event model that holds, among other things, the IP address of the request. So the easy answer is to geolocate instances of that model when they're created or updated:
[sourcecode language='ruby']
class Event < ActiveRecord::Base
before_save :get_country_info
def get_country_info
segments = remote_ip.split('.')
ip_atom = ((segments[0].to_i * 256 + segments[1].to_i) * 256 + segments[2].to_i)*256
result = connection.execute("SELECT * FROM `ip_group_country` where `ip_start` <= #{ip_atom} order by ip_start desc limit 1;")
row = result.fetch_row
self.country_code = row[2]
self.country_name = row[3]
end
end
[/sourcecode]
3) There is no #3. That's it!
There are various services that will let you geolocate based on IP just by making an API call. But there's no particular reason to go outside your own application for this; it's pretty trivial to set up in Rails:
1) Download the "Complete (Country) One Table" SQL file from IPInfoDB. This is the raw data necessary to do the lookups. Decompress it and then run the resulting SQL file in your application's database. This will give you an
ip_group_country
table. There's no need to set up a matching model; we're just going to hit it with raw SQL.2) In this particular application, we're maintaining an Event model that holds, among other things, the IP address of the request. So the easy answer is to geolocate instances of that model when they're created or updated:
[sourcecode language='ruby']
class Event < ActiveRecord::Base
before_save :get_country_info
def get_country_info
segments = remote_ip.split('.')
ip_atom = ((segments[0].to_i * 256 + segments[1].to_i) * 256 + segments[2].to_i)*256
result = connection.execute("SELECT * FROM `ip_group_country` where `ip_start` <= #{ip_atom} order by ip_start desc limit 1;")
row = result.fetch_row
self.country_code = row[2]
self.country_name = row[3]
end
end
[/sourcecode]
3) There is no #3. That's it!