RubyClicky: A ruby library for the API v0.1

May 28th, 2009

There is a great web analytics service called GetClicky which blows Google Analytics out of the water. For one thing, they have an API that allows your servers to log information that might not be able to happen with the traditional jScript include.

This might be processed information that happens after a page view due to a background process, or information that needs to be logged in between page views such as a redirect. An example is when you want to 301 or 302 redirect someone off-site – the user will never see a page in between on which you can include a jScript analytics logger. The GetClicky API allows your server to log that redirect.

GetClicky has an example PHP library for accessing their API but no Ruby lirbary (useful for Ruby On Rails development). Here is a simple port of that example code for accessing the GetClicky API with Ruby. Please comment to provide your feedback. New versions of the code will be published on this blog. It might get packaged into a RubyGem in the near future.


Drop this file into your Rails project lib directory, perhaps name it rubyclicky.rb. Add this to your environment.rb:

require "#{RAILS_ROOT}/lib/rubyclicky.rb"

This example controller method would redirect a user to GetClicky with a 302 and log the event in GetClicky:

def redirect
        href = request.request_uri
        if (href =~ /^https?/).nil?
          href = "#{request.protocol}#{request.domain(2)}#{request.request_uri}"
       GetClicky.log(:href => href,
                    :ip_address => request.remote_ip,
                    :type => "outbound",
                    :ref => request.referer,
                    :ua => request.env["HTTP_USER_AGENT"])
    response.redirect ""

The library code:

#RubyClicky A ruby library to access the API
#Copyright (C) 2009 John Nagro
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; either version 2
#of the License, or (at your option) any later version.
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#GNU General Public License for more details.
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
# Basically a straight port of GetClicky official PHP API function
require 'uri'
require 'open-uri'
class GetClicky
  SITE_ID = "123"
  SITEKEY_ADMIN = "123abc"
  VALID_TYPES = ["pageview", "download", "outbound", "click", "custom", "goal"]
  def self.log(args)
    type = args[:type]
    type = "pageview" unless VALID_TYPES.include?(type)
    base_uri = "{SITE_ID}&srv=#{DATABASE_SERVER}&sitekey_admin=#{SITEKEY_ADMIN}&type=#{type}"
    # we need either a session_id or an ip_address...
      base_uri += "&session_id=#{args[:session_id.to_i]}"
    elsif( (args[:ip_address] =~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) != nil )
      base_uri += "&ip_address=#{args[:ip_address]}"
      return false
    # goals can come in as integer or array, for convenience
      base_uri += "&goal=#{args[:goal]}"
    elsif(args[:goal].is_a?(Hash) && args[:goal][:id].is_a?(Numeric))
      args[:goal].each do |key,value|
        base_uri += "&goal[#{URI.escape(key)}]=#{URI.escape(value)}"
    # custom data, must come in as array of key=>values
      args[:custom].each do |key,value|
        base_uri += "&custom[#{URI.escape(key)}]=#{URI.escape(value)}"
    case args[:type]
    when "outbound"
      return false unless (args[:href] =~ /^(https?|telnet|ftp)/) != nil
      # all other action types must start with either a / or a #
      args[:href] = "/#{args[:href]}" if((args[:href] =~ /^(\/|\#)/) == nil)
    base_uri += "&href=#{URI.escape(args[:href])}"
      base_uri += "&title=#{URI.escape(args[:tite])}"
      base_uri += "&ref=#{URI.escape(args[:ref])}"
      base_uri += "&ua=#{URI.escape(args[:ua])}"
    return open(base_uri) ? true : false

Heredoc in C-sharp (C#)

February 3rd, 2009

Heredocs are very useful when embedding string-literal text in code. The C# syntax is to start a quote with an @ sign, like so:

string hereDocExample = @"Here is an example string in heredoc
   notice the formatting
           doesn't interpret nt

Results in:

Here is an example string in heredoc
   notice the formatting
           doesn't interpret nt

It’s obviously immediately useful for pre-formated output, but I’ve found it useful for other things like mini templates in small snippets of code. Here is a simple String.Format example:

string miniTemplate = @"Hello {0},
Your friend {1} sent you this message:
That's all!";
string populatedTemplate = String.Format(miniTemplate, "Fred", "Jack", "HelloWorld!");

Results in:

Hello Fred,
Your friend Jack sent you this message:
That's all!


Rails Inflection Of “Metadata” and “Data”

February 3rd, 2009

Although, it’s grammatically correct to use “metadatum” and “datum” as the singular forms of “metadata” and “data”, sometimes you run into situations where you’ve already chosen to use “data” and “datas”, “metadata” and “metadatas” (dumb I know). If you’ve done this, and choose to use methods like classify, you might run into problems. Here is an example Inflector fix for rails to change the singular form of each, in envrionment.rb:

Inflector.inflections do |inflect|
  inflect.singular 'data', 'data'
  inflect.singular 'metadata', 'metadata'

A Hash of Arrays and a Hash of Hashes in Ruby

November 13th, 2008

If you want to create a hash with a default value of an empty array use this:{|hash, key| hash[key] =}

The same is true for a hash of hashes:{|hash, key| hash[key] =}

Normally one would think to use:

But that is simply creating 1 array object, and assigning it as the default value, which results in situations like this:

# a new hash
h =
# default value for an unassigned key is as 
# expected, an empty array
=> []
# another unassigned key, also an empty array
=> []
# now, lets alter the first key "one"
h["one"].push 1
=> [1]
# notice this other unassigned key was altered
# which illustrates the single array object as the 
# default value for all unassigned keys
=> [1]

To create a hash with a default value of a hash who’s default value is an array, use this:{|hash, key| hash[key] ={|hash, key| hash[key] =}}

Which works like this:

# a new hash of hashes of arrays
hha ={|hash, key| hash[key] ={|hash, key| hash[key] =}}
# an unassigned key
=> {}
# an unassigned key in the default hash
=> []


Ruby on Rails Redirect to a Secure Page (SSL)

July 9th, 2008

Apache redirects and rewrites are usually easiest to work with when forcing SSL. However, a ruby on rails controller before filter used to redirect a user to a secure version of a page (SSL) might look like this:

def redirect_to_ssl
  if request.ssl? || local_request?
    return true
    redirect_to url_for params.merge({:protocol => 'https://'})
    return false

Your mileage may vary. This could be destructive to pages that accept GET variables to do bad things. The return false will halt the execution chain, which is the “correct” practice and avoids processing destructive GET variables twice. This probably won’t work properly on incoming POST requests because it will try to redirect the POST, so check where your forms are posting to. You might consider altering the code to accept posts, even during the insecure case (non-ssl), but is not recommended. It would look something like this:

def redirect_to_ssl
  if request.ssl? || local_request? ||
    return true
    redirect_to url_for params.merge({:protocol => 'https://'})
    return false

Inspiration found in a posting and comments here:

Merge two Arrays together into a Hash in Ruby

June 10th, 2008

Lets say you have two arrays that you want to be turned into a hash of keys and values in Ruby. This is an efficient way to that:

def Hash.from_pairs(keys,values)
  hash = {}
  keys.size.times { |i| hash[ keys[i] ] = values[i] }

Although this looks nice, it’s very slow:



Auto-Indent In IRB

May 14th, 2008

To add auto-indent to your Interactive Ruby Shell (IRB) add this snippet to your ~/.irbrc

IRB.conf[:AUTO_INDENT] = true

As you open and close blocks, IRB will automatically indent your cursor.