How to Install Latest Ruby on Rails on Ubuntu Linux

After pulling MUCH of my hair (not that I have much left), finally found out the BEST solution from this blog post

  1. Download and install VirtualBox
  2. Download an ISO of Ubuntu 11.04
  3. Create a VM from the Ubuntu ISO
  4. Launch a terminal and prepare Ubuntu for Ruby (instructions adapted from this site)
    1. sudo -i
    2. apt-get update
    3. apt-get -y install build-essential zlib1g zlib1g-dev libxml2 libxml2-dev libxslt-dev libopenssl-ruby libcurl4-openssl-dev libssl-dev mysql-server
    4. apt-get -y install git-core
    5. apt-get -y install curl wget
  5. Now, build and install Ruby from source (sudo is implied)
    1. cd /usr/local/src
    2. wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.2-p180.tar.gz
    3. tar -xvf ruby-1.9.2-p180.tar.gz
    4. cd ruby-1.9.2-p180
    5. ./configure
    6. make
    7. make install
  6. Install the gems, including Rails and Passenger, as well as the web server, nginx
    1. gem install rails
    2. gem install passenger
    3. passenger-install-nginx-module
  7. If you receive an OpenSSL error, follow these steps:
    1. cd /usr/local/src/ruby-1.9.2-p0/ext/openssl
    2. ruby extconf.rb
    3. make
    4. make install
  8. Configure nginx to run as a service and to start with the vm (instructions adapted from this site)
    1. adduser –system –no-create-home –disabled-login –disabled-password –group nginx
    2. gedit /etc/init.d/nginx (paste the following code in the file and save it)
    3. #! /bin/sh### BEGIN INIT INFO
      # Provides:          nginx
      # Required-Start:    $all
      # Required-Stop:     $all
      # Default-Start:     2 3 4 5
      # Default-Stop:      0 1 6
      # Short-Description: starts the nginx web server
      # Description:       starts nginx using start-stop-daemon
      ### END INIT INFOPATH=/opt/nginx/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
      DAEMON=/opt/nginx/sbin/nginx
      NAME=nginx
      DESC=nginxtest -x $DAEMON || exit 0# Include nginx defaults if available
      if [ -f /etc/default/nginx ] ; then
      . /etc/default/nginx
      fi
      set -e
      . /lib/lsb/init-functions
      case "$1" in
      start)
      echo -n "Starting $DESC: "
      start-stop-daemon --start --quiet --pidfile /opt/nginx/logs/$NAME.pid \
      --exec $DAEMON -- $DAEMON_OPTS || true
      echo "$NAME."
      ;;
      stop)
      echo -n "Stopping $DESC: "
      start-stop-daemon --stop --quiet --pidfile /opt/nginx/logs/$NAME.pid \
      --exec $DAEMON || true
      echo "$NAME."
      ;;
      restart|force-reload)
      echo -n "Restarting $DESC: "
      start-stop-daemon --stop --quiet --pidfile \
      /opt/nginx/logs/$NAME.pid --exec $DAEMON || true
      sleep 1
      start-stop-daemon --start --quiet --pidfile \
      /opt/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
      echo "$NAME."
      ;;
      reload)
      echo -n "Reloading $DESC configuration: "
      start-stop-daemon --stop --signal HUP --quiet --pidfile /opt/nginx/logs/$NAME.pid \
      --exec $DAEMON || true
      echo "$NAME."
      ;;
      status)
      status_of_proc -p /opt/nginx/logs/$NAME.pid "$DAEMON" nginx && exit 0 || exit $?
      ;;
      *)
      N=/etc/init.d/$NAME
      echo "Usage: $N {start|stop|restart|reload|force-reload|status}" >&2
      exit 1
      ;;
      esac
      exit 0

    4. chmod +x /etc/init.d/nginx
    5. /usr/sbin/update-rc.d -f nginx defaults
    6. /etc/init.d/nginx start
  9. Done

In step 6, command “gem” might not be installed correctly.. in that case, do this

1. Download latest ruby gems (.tgz) from here

2. unzip, then run “ruby setup.rb”

3. VOILA

Codeigniter Zipcode/Distance Calculator

Port of Micah Carrick’s PHP Zip Code Range and Distance Calculation for Codeigniter:

application/plugins/zipcode_pi.php

 

 *      v1.0.0 [Apr 12, 2005] - Initial Version
 *
 *******************************************************************************
 *  DESCRIPTION:

 *    A PHP Class and MySQL table to find the distance between zip codes and
 *    find all zip codes within a given mileage or kilometer range.
 *
 *******************************************************************************
*/

// constants for setting the $units data member
define('_UNIT_MILES', 'm');
define('_UNIT_KILOMETERS', 'k');

// constants for passing $sort to get_zips_in_range()
define('_ZIPS_SORT_BY_DISTANCE_ASC', 1);
define('_ZIPS_SORT_BY_DISTANCE_DESC', 2);
define('_ZIPS_SORT_BY_ZIP_ASC', 3);
define('_ZIPS_SORT_BY_ZIP_DESC', 4);

// constant for miles to kilometers conversion
define('_M2KM_FACTOR', 1.609344);

class Zipcode {

   var $last_error = "";            // last error message set by this class
   var $last_time = 0;              // last function execution time (debug info)
   var $units = _UNIT_MILES;        // miles or kilometers
   var $decimals = 2;               // decimal places for returned distance
   var $CI;

   function Zipcode()
   {
      $this->CI =& get_instance();
      $this->CI->load->model('zipcode_model');
   }

   function get_distance($zip1, $zip2) {

      // returns the distance between to zip codes.  If there is an error, the
      // function will return false and set the $last_error variable.

      $this->chronometer();         // start the clock

      if ($zip1 == $zip2) return 0; // same zip code means 0 miles between. :) 

      // get details from database about each zip and exit if there is an error

      $details1 = $this->get_zip_point($zip1);
      $details2 = $this->get_zip_point($zip2);
      if ($details1 == false) {
         $this->last_error = "No details found for zip code: $zip1";
         return false;
      }
      if ($details2 == false) {
         $this->last_error = "No details found for zip code: $zip2";
         return false;
      }     

      // calculate the distance between the two points based on the lattitude
      // and longitude pulled out of the database.

      $miles = $this->calculate_mileage($details1[0], $details2[0], $details1[1], $details2[1]);

      $this->last_time = $this->chronometer();

      if ($this->units == _UNIT_KILOMETERS) return round($miles * _M2KM_FACTOR, $this->decimals);
      else return round($miles, $this->decimals);       // must be miles

   }   

	function get_zip_code($city, $state)
	{
		$rows = $this->CI->zipcode_model->get_zip_code($city, $state);
		if(count($rows) == 0)
			return FALSE;
		return $rows[0]->zip_code;
	}

   function get_zip_details($zip) {

      // This function pulls the details from the database for a
      // given zip code.
      $row = $this->CI->zipcode_model->get_zip_details($zip);

      if(count($row) == 0 )
      {
         return FALSE;
      }

      return array("latitude" => $row[0]->latitude,
                   "longitude" => $row[0]->longitude,
                   "city" => $row[0]->city,
                   "county" => $row[0]->county,
                   "state_prefix" =>$row[0]->state_prefix,
                   "state_name" =>$row[0]->state_name,
                   "area_code" =>$row[0]->area_code,
                   "time_zone" => $row[0]->time_zone);

   }

   function get_zip_point($zip) {

      $row = $this->CI->zipcode_model->get_zip_point($zip);

      if(count($row) == 0 )
      {
         return FALSE;
      }

      return array($row[0]->lat,$row[0]->lon);

   }

   function calculate_mileage($lat1, $lat2, $lon1, $lon2) {

      // used internally, this function actually performs that calculation to
      // determine the mileage between 2 points defined by lattitude and
      // longitude coordinates.  This calculation is based on the code found
      // at http://www.cryptnet.net/fsp/zipdy/

      // Convert lattitude/longitude (degrees) to radians for calculations
      $lat1 = deg2rad($lat1);
      $lon1 = deg2rad($lon1);
      $lat2 = deg2rad($lat2);
      $lon2 = deg2rad($lon2);

      // Find the deltas
      $delta_lat = $lat2 - $lat1;
      $delta_lon = $lon2 - $lon1;

      // Find the Great Circle distance
      $temp = pow(sin($delta_lat/2.0),2) + cos($lat1) * cos($lat2) * pow(sin($delta_lon/2.0),2);
      $distance = 3956 * 2 * atan2(sqrt($temp),sqrt(1-$temp));

      return $distance;
   }

	function get_city_states($zips)
	{
		$rows = $this->CI->zipcode_model->get_city_states($zips);
		if(count($rows) == 0)
			return FALSE;

		$city_states = array();
		foreach($rows as $row)
		{
			$city_states["city"] = $row->city;
			$city_states["state_prefix"] = $row->state_prefix;
		}
		return $city_states;
	}

   function get_zips_in_range($zip, $range, $sort=1, $include_base) {

      // returns an array of the zip codes within $range of $zip. Returns
      // an array with keys as zip codes and values as the distance from
      // the zipcode defined in $zip.

      $this->chronometer();                     // start the clock

      $details = $this->get_zip_point($zip);  // base zip details
      if ($details == false) return false;

      // This portion of the routine  calculates the minimum and maximum lat and
      // long within a given range.  This portion of the code was written
      // by Jeff Bearer (http://www.jeffbearer.com). This significanly decreases
      // the time it takes to execute a query.  My demo took 3.2 seconds in
      // v1.0.0 and now executes in 0.4 seconds!  Greate job Jeff!

      // Find Max - Min Lat / Long for Radius and zero point and query
      // only zips in that range.
      $lat_range = $range/69.172;
      $lon_range = abs($range/(cos($details[0]) * 69.172));
      $min_lat = number_format($details[0] - $lat_range, "4", ".", "");
      $max_lat = number_format($details[0] + $lat_range, "4", ".", "");
      $min_lon = number_format($details[1] - $lon_range, "4", ".", "");
      $max_lon = number_format($details[1] + $lon_range, "4", ".", "");

      $rows = $this->CI->zipcode_model->get_zips_in_range($zip,$min_lat, $max_lat,$min_lon,$max_lon,$include_base);

      if(count($rows) == 0 )
      {
         return FALSE;
      }

      $return = array();    // declared here for scope

      foreach($rows as $row)
      {
         // loop through all 40 some thousand zip codes and determine whether
         // or not it's within the specified range.

         // calculate_mileage($lat1, $lat2, $lon1, $lon2)
         // $dist = $this->calculate_mileage($details[0],$row[1],$details[1],$row[2]);
         $dist = $this->calculate_mileage($details[0], $row->lat, $details[1], $row->lon);
         if ($this->units == _UNIT_KILOMETERS) $dist = $dist * _M2KM_FACTOR;
         if ($dist <= $range) {
            $return[] = array(
				"city"		=> $row->city,
				"state"		=> $row->state_prefix,
				"zip_code"	=> $row->zip_code,
				"distance" 	=> round($dist, $this->decimals));
         }
      }

      // sort array
      switch($sort)
      {
         case _ZIPS_SORT_BY_DISTANCE_ASC:
            usort($return, array($this, "distance_sort_asc"));
            break;

         case _ZIPS_SORT_BY_DISTANCE_DESC:
            usort($return, array($this, "distance_sort_desc"));
            break;

         case _ZIPS_SORT_BY_ZIP_ASC:
            usort($return, array($this, "zip_code_sort_asc"));
            break;

         case _ZIPS_SORT_BY_ZIP_DESC:
            usort($return, array($this, "zip_code_sort_desc"));
            break;
      }

      $this->last_time = $this->chronometer();

      if (empty($return)) return false;
      return $return;
   }

	function chronometer()
	{
	   // chronometer function taken from the php manual.  This is used primarily
	   // for debugging and anlyzing the functions while developing this class.  

	   $now = microtime(TRUE);  // float, in _seconds_
	   $now = $now + time();
	   $malt = 1;
	   $round = 7;

	   if ($this->last_time > 0) {
	       /* Stop the chronometer : return the amount of time since it was started,
	       in ms with a precision of 3 decimal places, and reset the start time.
	       We could factor the multiplication by 1000 (which converts seconds
	       into milliseconds) to save memory, but considering that floats can
	       reach e+308 but only carry 14 decimals, this is certainly more precise */

	       $retElapsed = round($now * $malt - $this->last_time * $malt, $round);

	       $this->last_time = $now;

	       return $retElapsed;
	   } else {
	       // Start the chronometer : save the starting time

	       $this->last_time = $now;

	       return 0;
	   }
   }

   function zip_code_sort_asc($a, $b)
	{
		return $this->sortAscend($a, $b, "zip_code");
	}

	function zip_code_sort_desc($a, $b)
	{
		return $this->sortDescend($a, $b, "zip_code");
	}

	function distance_sort_asc($a, $b)
	{
		return $this->sortAscend($a, $b, "distance");
	}

	function distance_sort_desc($a, $b)
	{
		return $this->sortDescend($a, $b, "distance");
	}

	function sortAscend($a, $b, $key)
	{
	   if ($a[$key] == $b[$key]) {
	        return 0;
	    }
	    return ($a[$key] < $b[$key] ) ? -1 : 1;
	}

	function sortDescend($a, $b, $key)
	{
	   if ($a[$key] == $b[$key]) {
	        return 0;
	    }
	    return ($a[$key] < $b[$key] ) ? 1 : -1;
	}
}
?>

And the model

application/model/zipcode_model.php

db->query($select.$from.$where.$order);
		return $query->result();
	}

	function get_zip_details($zip)
	{
		$sql = "SELECT lat AS latitude, lon AS longitude, city, county, state_prefix,
              state_name, area_code, time_zone
              FROM zip_code
              WHERE zip_code='$zip'";

		$query = $this->db->query($sql);
		return $query->result();
	}

	function  get_zip_point($zip)
	{
      $sql = "SELECT lat, lon from zip_code WHERE zip_code='$zip'";
		$query = $this->db->query($sql);
		return $query->result();
	}

	function get_city_states($zip_codes)
	{
		$sql = "select distinct city, state_prefix from zip_code where zip_code in (". implode(", ", $zip_codes).")";
		$query = $this->db->query($sql);
		return $query->result();

	}

	function get_zips_in_range($zip,$min_lat, $max_lat,$min_lon,$max_lon, $include_base)
	{
		$sql = "SELECT * FROM zip_code ";
	    if (!$include_base) $sql .= "WHERE zip_code <> '$zip' AND ";
	    else $sql .= "WHERE ";
	    $sql .= "lat BETWEEN '$min_lat' AND '$max_lat' AND lon BETWEEN '$min_lon' AND '$max_lon'";

		$query = $this->db->query($sql);
		return $query->result();
	}

	function get_zip_code($city, $state)
	{
		$sql = "select zip_code from zip_code where city = '".($city)."' and state_prefix='".$state."' limit 1";
		$query = $this->db->query($sql);
		return $query->result();
	}

}
?>

Related Blogs

MaxMind GeoIP.js blocked on your site? Make your own GeoIP locator service

If you send too much traffic to MaxMind’s geo-IP location service, they will cut you off. Ok, maybe they just don’t like you. In fact, they’ll give you this warning/error:

<!DOCTYPE HTML PUBLIC “-//IETF//DTD HTML 2.0//EN”>
<html>

<head><title>302 Found</title></head>

<body>
<h1>Found</h1>
<p>The document has moved <a href=”http://j.maxmind.com:666//app/geoip.js”>here</a>.</p>
<hr>
<address>Apache/2.2.11 (Unix) mod_ssl/2.2.11 OpenSSL/0.9.7a Server at www.maxmind.com Port 80</address>
</body>

</html>

Yes, gay indeed.

If you need their service, you might want to try implementing your own service with their downloadable database. They have several methods of quering the database. If you have linux knowledge, I highly recommend the Linux/Apache method (it’s super fast and super easy to install):

Here are steps, for people who are operating Ubuntu/Debian

1. Download the database as outlined here:

wget -N -q http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz

2. Install the mod_ip for apache as outlined here:

apt-get install libapache2-mod-geoip

emacs vi /etc/apache2/mods-available/geoip.conf

(modify geoip.conf to this)

<IfModule mod_geoip.c>
  GeoIPEnable On
  GeoIPDBFile /path/to/your/GeoLiteCity.dat
</IfModule>

/etc/init.d/apache2 restart

Now you can query the IP location from your PHP like so:

<html>
<body>
<?php
$country_code = apache_note(“GEOIP_COUNTRY_CODE”);
$region = apache_note(“GEOIP_REGION”);
$city = apache_note(“GEOIP_CITY”);

echo $city. “, “. $region;
?>
</body>
</html>

Voila!