How to get a visitor IP address in Ruby on Rails
The most obvious solution is to call request.ip, which returns the client's IP address. However, when you deploy your application in production and depending on your host's infrastructure, you may get an incorrect result.
For example, if your website is behind a reverse proxy, every call to request.ip will return the proxy's IP address, not the visitor's.
Luckily the request object provides another interesting method: remote_ip. It has to be understood that, even if request is an ActionDispatch::Request object, its method remote_ip is actually a proxy for the ActionDispatch::RemoteIp middleware.
request.remote_ip checks all IPs present in the HTTP header, looking for fields generally used by firewalls, load balancers, or proxies, such as HTTP_X_FORWARDED_FOR, and make a guess to return what seems to be the correct visitor's IP address.
You should use request.remote_ip only if you are behind a proxy or a firewall, or you would be vulnerable to IP spoofing attacks: as request.remote_ip checks for fields in the HTTP header that proxies usually set, and if you are not behind a proxy, then anyone could manually set a false IP address in the headers. Doing so is as simple as this:
curl -H "X-Forwarded-For: 5.5.5.5" http://your.website.com
So before choosing between request.ip and request.remote_ip to get your visitors' IP addresses, you need to know a little about your host infrastructure. You could eventually analyze the HTTP headers when a request reaches your application to understand from which header you can get the real IP address.
Doing geolocation in Ruby
As mentioned above, your visitors' IP address can be used to understand better your audience's demographics, which you can analyze to gain huge advantages in marketing and content targeting.
The less costly approach is to call an external API to translate your visitor's IP addresses to their physical location. Abstract IP Geolocation API provide GPS coordinates, country, city, timezone, and a visitor's currency from its IP address with a simple GET request.
After creating a free account, you obtain your personal API key and can start fetching information. Here is an example of implementation:
require 'net/http'
require 'net/https'
def make_abstract_request(api_key, ip_address)
uri = URI('https://ipgeolocation.abstractapi.com/v1/?api_key=#{api_key}&ip_address=#{ip_address}')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Get.new(uri)
response = http.request(request)
puts "Status code: #{ response.code }"
puts "Response body: #{ response.body }"
rescue StandardError => error
puts "Error (#{ error.message })"
end
api_key = "THE_API_KEY_IN_YOUR_DASHBOARD"
ip_address = "IP_ADDRESS"
make_abstract_request(api_key, ip_address)
Here is an example of a response:
{
"ip_address": "17.52.21.100",
"city": "Cupertino",
"city_geoname_id": 5341145,
"region": "California",
"region_iso_code": "CA",
"region_geoname_id": 5332921,
"postal_code": "95014",
"country": "United States",
"country_code": "US",
"country_geoname_id": 6252001,
"country_is_eu": false,
"continent": "North America",
"continent_code": "NA",
"continent_geoname_id": 6255149,
"longitude": -122.03,
"latitude": 37.3219,
"security": {
"is_vpn": false
},
"timezone": {
"name": "America/Los_Angeles",
"abbreviation": "PST",
"gmt_offset": -8,
"current_time": "01:43:33",
"is_dst": false
},
"flag": {
"emoji": "🇺🇸",
"unicode": "U+1F1FA U+1F1F8",
"png": "https://static.abstractapi.com/country-flags/US_flag.png",
"svg": "https://static.abstractapi.com/country-flags/US_flag.svg"
},
"currency": {
"currency_name": "USD",
"currency_code": "USD"
},
"connection": {
"autonomous_system_number": 714,
"autonomous_system_organization": "Apple Inc.",
"connection_type": "Corporate",
"isp_name": "Apple Inc.",
"organizaton_name": "Apple Inc"
}
}


