Very interesting article ‘User Analytics for Rails Apps’ written by Bala Paranj at Rubyplus.com, here is the link of the original post: https://rubyplus.com/articles/4051-User-Analytics-for-Rails-Apps

Getting IP Address

  • Extract the IP from the request in the controller:
    request.remote_ip
    
  • Getting Location details from IP Use Geocoder gem.
    > r = Geocoder.search('209.249.19.172').first
     => #<Geocoder::Result::Freegeoip:0x007fc02ae9ad80 @data={"ip"=>"209.249.19.172", "country_code"=>"US", "country_name"=>"United States", "region_code"=>"CA", "region_name"=>"California", "city"=>"Moraga", "zip_code"=>"94556", "time_zone"=>"America/Los_Angeles", "latitude"=>37.8381, "longitude"=>-122.1026, "metro_code"=>807}, @cache_hit=nil>
    > r.class
     => Geocoder::Result::Freegeoip
    > r.data
     => {"ip"=>"209.249.19.172", "country_code"=>"US", "country_name"=>"United States", "region_code"=>"CA", "region_name"=>"California", "city"=>"Moraga", "zip_code"=>"94556", "time_zone"=>"America/Los_Angeles", "latitude"=>37.8381, "longitude"=>-122.1026, "metro_code"=>807}
    > r.data['ip']
     => "209.249.19.172"
    > r.data['country_name']
     => "United States"
    > r.data['region_name']
     => "California"
    > r.data['city']
     => "Moraga"
    > r.ip
     => "209.249.19.172"
    > r.country
     => "United States"
    > r.state
     => "California"
    > r.postal_code
     => "94556"
    > r.city
     => "Moraga"
    

    Save the IP in the database and geocode in the background using background jobs.

Getting the Search Keyword

Use referer-parser gem.

require 'referer-parser'
rf = RefererParser::Parser.new.parse('http://www.google.com/search?q=gateway+oracle+cards+denise+linn&hl=en&client=safari')
 => {:known=>true, :uri=>"http://www.google.com/search?q=gateway+oracle+cards+denise+linn&hl=en&client=safari", :source=>"Google", :medium=>"search", :domain=>"google.com", :term=>"gateway oracle cards denise linn"}
> rf.class
 => Hash
> rf
 => {:known=>true, :uri=>"http://www.google.com/search?q=gateway+oracle+cards+denise+linn&hl=en&client=safari", :source=>"Google", :medium=>"search", :domain=>"google.com", :term=>"gateway oracle cards denise linn"}
> rf[:term]
 => "gateway oracle cards denise linn"
> rf[:domain]
 => "google.com"
> rf[:uri]
 => "http://www.google.com/search?q=gateway+oracle+cards+denise+linn&hl=en&client=safari"
> rf[:source]
 => "Google"

In the controller pass request.referer to the parse method. Save the request.referer in the database and use referer-parser gem to extract details in a background job. This will not work if the user is signed-in to Google.

You will get the error:

Exception occurred : Only HTTP and HTTPS schemes are supported --

for direct traffic source. The reason is referer value will be nil and the library will throw this meaningless exception. You can identify direct traffic source:

if request.referer.nil?
  logger.info 'Traffice source : Direct'
end

The precondition is not satisfied. So, ideally the library should throw an exception saying that it cannot parse nil to find the referer.

Find the Referring Domain

Use addressable gem. Add it to Gemfile.

gem 'addressable'

The value of request.referer provides the referring domain. The standard URI library in ruby sometimes drops parts of the URL. It also has problems handling special characters in URLs like these: ™ ‘ ’ ° ®. Addressable ruby gem from sporkmonger on git hub is a perfect solution. So use this gem to find the referring domain.

referring_domain = Addressable::URI.parse('http://www.google.com/search?q=gateway+oracle+cards+denise+linn&hl=en&client=safari').host
 => "www.google.com"

Save the request.referer in the database. Do this processing in a background job.

Browser Details

User browser gem to extract browser related information.

require "browser"
> user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36'
 => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36"
    browser = Browser.new(user_agent, accept_language: "en-us")
 => #<Browser::Chrome:0x007f9772913488 @ua="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36", @accept_language=[#<Browser::AcceptLanguage:0x007f9772913348 @part="en-us", @quality=1.0>]>
> browser.name
 => "Chrome"
> browser.bot?
 => false
> browser.version
 => "49"
> browser.device
 => #<Browser::Device:0x007f97729621c8 @ua="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36">
> browser.device.name
 => "Unknown"
> browser.device.id
 => :unknown
> browser.platform
 => #<Browser::Platform:0x007f97730b8e68 @ua="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36">
> browser.platform.name
 => "Macintosh"

You can pass the user agent to the browser constructor by calling:

request.user_agent

in the controller.

Tracking New Visitors

In the controller, set a cookie when a visitor comes to your site if they don’t already have value for ma_visit cookie.

unless browser.bot?
  unless cookies[:ma_visit].present?
    # Sets a "permanent" cookie (which expires in 20 years from now).
    cookies.permanent[:ma_visit] = "some-unique-string-for-every-browser"
  end
end

A visit is new if the ma_visit cookie does not exist.

def new_visit?
  !existing_visit_id
end

def existing_visit_id
  request.cookies["ma_visit"])
end

To generate the unique string for the cookie use uuidtools gem. Add it to Gemfile.

gem 'uuidtools'

You can create an unique string like this:

> UUIDTools::UUID.random_create.to_s
 => "a5cd193b-b23f-4541-9238-8522b809e9e1"

User Agent Details

You can use user_agent_parser gem.

> require 'user_agent_parser'
 => false
> user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36'
 => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36"
> ua = UserAgentParser.parse user_agent
 => #<UserAgentParser::UserAgent Chrome 49.0.2623 (Mac OS X 10.10.5) (Other)>
> ua.to_s
 => "Chrome 49.0.2623"
> ua.family
 => "Chrome"
> ua.version
 => #<UserAgentParser::Version 49.0.2623>
> ua.version.to_s
 => "49.0.2623"
> ua.version.major
 => "49"
> ua.version.minor
 => "0"
> ua.os.to_s
 => "Mac OS X 10.10.5"

These tips are based on the source code of ahoy_matey gem. It uses user_agent_parser gem to find the browser name and the OS. We can use the browser gem to give us that information.

References

referer-parser gem
Geocoder Gem
Browser Gem
Replacing Ruby’s URI with Addressable