<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Daddy Fixes Everything &#187; Ruby</title>
	<atom:link href="http://blog.spoolz.com/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.spoolz.com</link>
	<description>A father and programmer&#039;s skewed view of the world</description>
	<lastBuildDate>Sun, 26 Apr 2009 03:29:43 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Sinatra-Tailer: a small app for viewing server log files</title>
		<link>http://blog.spoolz.com/2009/03/18/sinatra-tailer-a-small-app-for-viewing-server-log-files/</link>
		<comments>http://blog.spoolz.com/2009/03/18/sinatra-tailer-a-small-app-for-viewing-server-log-files/#comments</comments>
		<pubDate>Wed, 18 Mar 2009 23:03:24 +0000</pubDate>
		<dc:creator>Karl</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[logs]]></category>
		<category><![CDATA[sinatra]]></category>
		<category><![CDATA[tail]]></category>

		<guid isPermaLink="false">http://blog.spoolz.com/?p=177</guid>
		<description><![CDATA[I was reading Jason Seifer&#8217;s: Offline Gem Server Rdocs, which is an apache/passenger served Sinatra app that allows you to view the Rdocs of installed gems without using gem server. Nice. So I installed it on our sandbox server for all to enjoy.
But it got me thinking, there is another think I like to keep [...]]]></description>
			<content:encoded><![CDATA[<p>I was reading <a href="http://jasonseifer.com/2009/02/22/offline-gem-server-rdocs">Jason Seifer&#8217;s: Offline Gem Server Rdocs</a>, which is an apache/passenger served <a href="http://www.sinatrar.com">Sinatra</a> app that allows you to view the Rdocs of installed gems without using <em>gem server</em>. Nice. So I installed it on our sandbox server for all to enjoy.</p>
<p>But it got me thinking, there is another think I like to keep an eye on on our servers&#8230; log files. Oh, and I was looking for good excuse to play around with Sinatra. So, &#8220;with a one, and-a-two, and-a-three&#8230;&#8221; we have <a href="http://github.com/threadhead/sinatra-tailer/tree">Sinatra-Tailer</a>.</p>
<p>You can <a href="http://github.com/threadhead/sinatra-tailer/tree">read all about it on the github page</a>, but in short it simply performs a <em>tail</em> and displays the last X lines of the log file.</p>
<pre class="brush: bash">
tail -n /path/to/my/log/file.log
</pre>
<h3>Features</h3>
<ol>
<li>refreshes the list every X seconds, set by the user</li>
<li>only one config.yml file to edit</li>
<li>supports file globs, so you can grab a whole list of file with one line</li>
<li>specify the number of lines to show</li>
<li>completely unobtrusive js, because I&#8217;m cool?</li>
</ol>
<h3>Requirements</h3>
<ol>
<ul><a href="http://www.sinatrarb.com">Sinatra framework</a> (tested on 0.9.1.1, earlier may work)</ul>
</ol>
<p>I whipped this up pretty quickly so I&#8217;m sure there are a few bugs. There is some testing for a few unit tests, but nothing functional.</p>
<p>One word of warning, if you want to put this on a production server my recommendation is to put it on a separate port (like 9876) and <strong>for heaven&#8217;s sake</strong>, at a minimum use http basic authentication. From the sinatra <a href="http://www.sinatrarb.com/intro.html">readme</a>:</p>
<pre class="brush: ruby">
 use Rack::Auth::Basic do |username, password|
    username == &#039;admin&#039; &amp;&amp; password == &#039;secret&#039;
  end
</pre>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.spoolz.com/2009/03/18/sinatra-tailer-a-small-app-for-viewing-server-log-files/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Apache Virtual Hosts, Rails, Rack, Passenger on Local Net</title>
		<link>http://blog.spoolz.com/2009/03/12/apache-virtual-hosts-rails-rack-passenger-on-local-net/</link>
		<comments>http://blog.spoolz.com/2009/03/12/apache-virtual-hosts-rails-rack-passenger-on-local-net/#comments</comments>
		<pubDate>Thu, 12 Mar 2009 19:51:03 +0000</pubDate>
		<dc:creator>Karl</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[rack]]></category>
		<category><![CDATA[sinatra]]></category>
		<category><![CDATA[virtual host]]></category>

		<guid isPermaLink="false">http://blog.spoolz.com/?p=143</guid>
		<description><![CDATA[This one has been bugging me for a couple of years and I just didn&#8217;t want to put in the time and testing to nail it down. But tonight was my night.
The Problem
Here in my development palace I have a couple of laptops that I use for development and an Ubuntu (hardy) server as a [...]]]></description>
			<content:encoded><![CDATA[<p>This one has been bugging me for a couple of years and I just didn&#8217;t want to put in the time and testing to nail it down. But tonight was my night.</p>
<h3>The Problem</h3>
<p>Here in my development palace I have a couple of laptops that I use for development and an Ubuntu (hardy) server as a <a href="http://rubyonrails.org/">Rails</a>/<a href="http://rack.rubyforge.org/">Rack</a> sandbox that I run with <a href="http://modrails.com">Passenger</a>. While I have always been able to serve up either a Rails or <a href="http://www.sinatrarb.com/">Sinatra</a> project, I typically have 3 or 4 going at the same time. But I had to access them with urls like: <em>http://192.168.0.2/project1</em> and <em>http://192.168.0.2/project2</em>.</p>
<p>So, what&#8217;s the problem, eh?</p>
<p>Well, for starters, you can&#8217;t do anything concerning subdomains. That&#8217;s a show stopper for many apps.</p>
<p>Second, it really messes with your environment variables like <em>["PATH_INFO"]</em>. So if you do any routing and you expect the base url to be <em>&#8216;/&#8217;</em>, it won&#8217;t be. The root url will be &#8216;/projectx&#8217;. Bummer.</p>
<h3>The Solution</h3>
<p>To remedy the issues with non-<a href="http://en.wikipedia.org/wiki/Top-level_domain">tld</a> virtual hosts (also called sub URIs?) we need to add the domains to the laptops and server, then add the virtualhosts on the server for apache. This means that I can now goto <em>http://project1.ubuntu.remote</em> url to get to my rails/rack app.</p>
<p>For reference, I am using the following:</p>
<ul>
<li>Laptops: Mac OS X, 10.5.7 and 10.4.11</li>
<li>Server: <a href="http://www.ubuntu.com/">Ubuntu</a> Desktop 8.04LTS, <a href="http://www.apache.org/">Apache</a>/2.2.8 (Ubuntu) <a href="http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html">mod_fastcgi</a>/2.4.6 PHP/5.2.4-2ubuntu5.5 with <a href="http://modrails.com">Suhosin-Patch Phusion_Passenger/2.0.6</a></li>
</ul>
<h4>On Each Laptop</h4>
<p>These instructions are for Mac OS X, but should be identical for your favorite flavor of *nix. We are going to add some friendly names to our ubuntu server using it&#8217;s ip address (192.168.0.2). In this example we will be able to access the root web documents using <em>http://ubuntu.remote</em>, and one of our Sinatra projects using <em>http://project1.ubuntu.remote</em>.</p>
<p><strong>Important!</strong> Don&#8217;t use a name ending in <em>&#8216;.local&#8217;</em>. While it did work for me, I read about a few instances where some systems will not resolve domain names ending in .local outside the local machine. Also, don&#8217;t change <strong>anything</strong> else in your /etc/hosts file except to add the lines at the end.</p>
<pre class="brush: python">
mate /etc/hosts

# add the following line to the END of your /etc/hosts file and save
# note: there is a &lt;space&gt; character between the ip address and each host name
192.168.0.2 ubuntu.remote project1.ubuntu.remote
</pre>
<h4>On The Server: Hosts File</h4>
<p>Nothing will work until we tell the server machine that it can accept incoming traffic from our new friendly names. Similar to on the mac, we need to edit our /etc/hosts file but we will add a slightly different line. In this case we are telling the server that incoming traffic from &#8216;ubuntu.remote&#8217; and &#8216;gems.ubuntu.remote&#8217; are just names for the localhost (127.0.0.1).</p>
<pre class="brush: shell">sudo pico /etc/hosts

# add the following line to the end of our /etc/hosts file and save
# you can added after your existing 127.0.0.1 line if you wish
127.0.0.1 ubuntu.remote project1.ubuntu.remote
</pre>
<h4>On The Server: VirtualHosts</h4>
<p>As a final step we will need to add or change the virtual host definitions for your rails/rack project. Depending on your Apache setup or Linux distro, the default enabled site may be slightly different and you may have to adapt your virtual host file to your default setup.</p>
<p>First, in my /etc/apache2/apache.conf file, I have the following line near the end of the file. This was to eliminate a warning every time apache was started/restarted. It may affect your virtual host default, but shouldn&#8217;t, so add it if you get errors.</p>
<pre class="brush: shell">
#added near end of /etc/apache2/apache.conf
ServerName localhost
</pre>
<p>Next we need to check our default virtual host setup to see how the NameVirtualHost is defined. We will duplicate that in each new virtual host that we add. The parts we are looking is the NameVirtualHost and VirtualHost near the top. They could be &#8216;NameVirtualHost *&#8217; and &#8216;&lt;VirtualHost *&gt;&#8217; or &#8216;NameVirtualHost *:80&#8242; and &#8216;&lt;VirtualHost *:80&gt;&#8217;. See the pattern? We need to use the same definition in our new virtual files.</p>
<p>Let&#8217;s check our default virtual host setup:</p>
<pre class="brush: shell">
cd /etc/apache2/sites-enabled
ls # your are looking for the name of your default site file

  total 0

  lrwxrwxrwx 1 root root 36 2009-02-27 18:49 000-default -&gt; /etc/apache2/sites-available/default

cat /etc/apache2/sites-enabled/000-default

  NameVirtualHost *
  &lt;VirtualHost *&gt;
    ServerAdmin webmaster@localhost
  # snipped several lines #
  &lt;/VirtualHost&gt;
</pre>
<p>On my system the NameVirtualHost is &#8216;*&#8217;, so that is what we need to use for the new virtual host. In this case, I am going to add a virtual host file for a rack based project. It&#8217;s a Sinatra app, but that doesn&#8217;t matter as this will work for any rack based project, even a rails/rack project (since rails 2.2.2?).</p>
<p>Also, I like using the Apache2 system to enable and disable sites. It&#8217;s clean, easy to use, and if any apache admin comes along they will know exactly what is going on.</p>
<p>It&#8217;s also work mentioning that you should disable or delete any existing virtual host files that you were using previously.</p>
<pre class="brush: shell">cd /etc/apache2/sites-available
sudo pico gems

# enter this as your virtual host setup
&lt;VirtualHost *&gt;
  ServerName project1.ubuntu.remote

  DocumentRoot &quot;/path/to/your/application/project/public&quot;

  RackEnv production
  &lt;directory &quot;/path/to/your/application/project/public&quot;&gt;
    Order allow,deny
    Allow from all
  &lt;/directory&gt;
&lt;/VirtualHost&gt;

# save the file and reload apache

sudo /etc/init.d/apache2 reload
</pre>
<h4>The Fun Part</h4>
<p>Assuming you saw no errors when you reloaded apache, you should be able to go to your new urls see both the root files and your rack application.</p>
<p>http://ubuntu.remote</p>
<p>http://project1.ubuntu.remote</p>
<p><strong>Dyn-O-Mite!</strong></p>
<h3>Bonus Points!</h3>
<p>For extra credit, let&#8217;s say you have admin access to your router, and you are one of those gotta-have-control-of-everything dudes (or dudettes) so you installed a 3rd party firmware. You&#8217;re in luck! You can probably add some custom entries in your DNS and you don&#8217;t have to edit the /etc/hosts files on your laptop.</p>
<p>I installed <a href="http://www.polarcloud.com/tomato/">Tomato firmware</a> on my Linksys wireless router. Tomato uses <a href="http://localhost:9292/doc_root/actionmailer-1.3.6/rdoc/index.html">Dnsmasq</a> with allows you to set internal host names.</p>
<p>Maybe I&#8217;ll cover that in another post.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.spoolz.com/2009/03/12/apache-virtual-hosts-rails-rack-passenger-on-local-net/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Ruby on Rails Ubuntu Server VM with VMPlayer</title>
		<link>http://blog.spoolz.com/2008/07/30/ruby-on-rails-ubuntu-server-vm-with-vmplayer/</link>
		<comments>http://blog.spoolz.com/2008/07/30/ruby-on-rails-ubuntu-server-vm-with-vmplayer/#comments</comments>
		<pubDate>Wed, 30 Jul 2008 23:15:41 +0000</pubDate>
		<dc:creator>Karl</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[vm]]></category>

		<guid isPermaLink="false">http://blog.spoolz.com/?p=21</guid>
		<description><![CDATA[I had to setup a Ubuntu (8.04) Server virtual machine and get Rails up-to-speed on it this morning, so I thought I would document my steps for those who find the need to repeat. Here is what I needed:

A production server, not a development server, with only what is necessary
A virtual machine that runs under [...]]]></description>
			<content:encoded><![CDATA[<p>I had to setup a Ubuntu (8.04) Server virtual machine and get Rails up-to-speed on it this morning, so I thought I would document my steps for those who find the need to repeat. Here is what I needed:</p>
<ul>
<li>A production server, not a development server, with only what is necessary</li>
<li>A virtual machine that runs under <a href="http://www.vmware.com/download/player/">VMware Player</a></li>
<li><a href="http://www.ubuntu.com/products/WhatIsUbuntu/serveredition">Ubuntu Server</a>, 8.04 is the current, referred to as Hardy Heron</li>
<li><a href="http://httpd.apache.org/">Apache2</a> with <a href="http://www.modrails.com">Phusion Passenger</a> to handle Rails applications</li>
<li><a href="http://www.ruby-lang.org/en/">Ruby</a>, <a href="http://rubyforge.org/projects/rubygems/">Rubygems</a>, <a href="http://www.rubyonrails.org/">Ruby on Rails</a>, a full Rails stack</li>
<li><a href="http://www.mysql.com/">MySQL Server</a> and <a href="http://www.sqlite.org/">SQLite</a>,  with <a href="http://www.phpmyadmin.net/">phpMyAdmin</a> to admin MySQL server</li>
<li>All native drivers for Rails (MySQL and SQLite)</li>
<li><a href="http://www.openssh.com/">OpenSSH</a> server to access the server</li>
<li><a href="http://www.postfix.org/">Postfix</a> to send (only) emails</li>
</ul>
<p>What you need to start:</p>
<p><span id="more-21"></span></p>
<ol>
<li>VMware Player installed. Download it from <a href="http://www.vmware.com/download/player/">VMware</a> directly and follow their instructions (aptitude has older version 1.x)</li>
<li><a href="http://www.ubuntu.com/getubuntu/download">Download the Ubuntu 8.04 Server ISO file</a> for your machine. For torrent users, <a href="http://releases.ubuntu.com/8.04/ubuntu-8.04.1-server-i386.iso.torrent">download the current i386 torrent file</a>.</li>
<li>Download my <a href="http://blog.spoolz.com/wp-content/uploads/2008/07/ubuntu840server.vmx">VMX</a> and <a href="http://blog.spoolz.com/wp-content/uploads/2008/07/ubuntu840servervmdk.zip">VMDK</a> files (vmplayer config and empty virtual disk).</li>
</ol>
<h3>Step 1: Setup Directory and Config File</h3>
<p>Create a new directory somwhere (I called mine &#8216;Ubuntu840Server&#8217;) and copy the Ubuntu ISO file and the VMX and VMDK (don&#8217;t forget to unzip) files into it. You will need to do some quick editing to the Ubuntu840Server.vmx file, so fire up your favorite editor (in Ubuntu Desktop, right-click and Open with &#8220;Text Editor&#8221;). The only sections you may need to edit are:</p>
<ul>
<li><em>ide1:1.filename</em>, make sure it matches the name of your ISO file, something like &#8220;ubuntu-8.04.1-serverr-i386.iso&#8221;</li>
<li><em>fileSearchPath</em>, change to the path of the directory you created</li>
</ul>
<h3>Step 2: Run VMWare Player</h3>
<p>Run VMware Player and open the Ubuntu840Server.vmx. If all the config settings are correct and the ISO files is in the directory, you should boot into Ubuntu Installer.</p>
<h3>Step 3: Install Ubuntu Server</h3>
<p>I won&#8217;t go into details here because Ubuntu has <a href="https://help.ubuntu.com/8.04/serverguide/C/index.html">step-by-step instructions on how to install</a>. But the short story is: <em>accept the defaults</em>.</p>
<p>There is one selection that will make installation easier, select LAMP Server when asked for the Software selection. <a href="http://en.wikipedia.org/wiki/LAMP_%28software_bundle%29">LAMP</a> stands for Linux/Apache/MySQL/PHP. It will install all those packages and configure them automatically for you.</p>
<p><a href="http://blog.spoolz.com/wp-content/uploads/2008/07/picture-1.png"><img class="alignnone size-medium wp-image-22" title="picture-1" src="http://blog.spoolz.com/wp-content/uploads/2008/07/picture-1-300x151.png" alt="" width="300" height="151" /></a></p>
<p>Note: even though I selected a LAMP server, for some reason it did not install Apache/Mysql/PHP. If this happens to you, just do the following after the server re-boots:</p>
<p><code>sudo apt-get install apache mysql-server php5 libapache2-mod-php5 php5-mysql<br />
</code></p>
<h3>Step 4: Get the Latest Updates</h3>
<p>If everything went well, you should reboot into Ubuntu Server and see the <em>login:</em> prompt. Go ahead and login with the username and password you supplied during the installation. Make sure you have the latest updates for Ubuntu by running (this may take a while):</p>
<p><code>sudo apt-get update<br />
sudo apt-get upgrade<br />
</code></p>
<h3>Step 5: Install OpenSSH</h3>
<p>I like to administer my VMs from the terminal via SSH. Ubuntu Server does not come preconfigured with an SSH server, so lets install one:</p>
<p><code>sudo apt-get install openssh-client<br />
sudo apt-get install openssh-server<br />
</code></p>
<p>You don&#8217;t really need the openssh-client, but I like to have it in case I ever need to ssh from the server to somewhere else. I can&#8217;t recommend enough that you secure your SSH server. If you server is exposed to the internet, <strong>it will be attacked</strong>, and one of the favorite vulnerabilities is SSH. Read this article on <a href="http://www.supportsmb.com/2007/02/20/how-to-secure-openssh/">how to Secure an OpenSSH Server</a>!</p>
<h3>Step 6: Install phpMyAdmin</h3>
<p>Since we are using MySQL, having a graphic administration program is nice and it&#8217;s hard to beat phpMyAdmin. I installed it from aptitude, but it did not set the proper aliases for apache2, so there are a few extra steps:</p>
<p><code>sudo apt-get install phpmyadmin</p>
<p># create a site file for apache2<br />
sudo pico /etc/apache2/sites-available/phpmyadmin</p>
<p># enter the following in pico<br />
Alias /phpmyadmin/ "/usr/share/phpmyadmin/"<br />
Alias /phpmyadmin "/usr/share/phpmyadmin/"<br />
&lt;Directory "/usr/share/phpmyadmin/" &gt;<br />
  Options Indexes FollowSymLinks MultiViews<br />
  AllowOverride None<br />
  Order allow,deny<br />
  Allow from all<br />
  Deny from none<br />
&lt;/Directory&gt;</p>
<p># close and save pico, then enter this to enable the phpmyadmin site<br />
sudo a2ensite phpmyadmin<br />
sudo /etc/init.d/apache2 restart<br />
</code></p>
<h3>Step 7: Install Ruby</h3>
<p>Next we need to install ruby. We&#8217;ll use the aptitude pre-built binaries to save time and make it easier to update in the future, but you may wish to install it from source. We also install the sqlite3 database because it is the default used by Rails 2.X and many test packages, but you can omit if you want.</p>
<p><code>sudo aptitude install ruby1.8-dev ruby1.8 ri1.8 rdoc1.8 irb1.8 libreadline-ruby1.8 libruby1.8 libopenssl-ruby sqlite3 libsqlite3-ruby1.8 build-essential mysql-client libmysqlclient15-dev postfix<br />
</code></p>
<p>Note that we installed the &#8216;build-essential&#8217; package. This package is necessary for you to install any other software from source (like native msql drivers and phusion passenger). We also install the postfix package, you can just accept the defaults.</p>
<p>Next you will need to set some symlinks so that the libraries will be located when needed.</p>
<p><code>sudo ln -s /usr/bin/ruby1.8 /usr/bin/ruby<br />
sudo ln -s /usr/bin/ri1.8 /usr/bin/ri<br />
sudo ln -s /usr/bin/rdoc1.8 /usr/bin/rdoc<br />
sudo ln -s /usr/bin/irb1.8 /usr/bin/irb<br />
</code></p>
<p>Now, when you should see your ruby package when you check the version from the terminal.</p>
<p><code>karl@ubuntuserver:~$ ruby -v<br />
ruby 1.8.6 (2007-09-24 patchlevel 111) [i486-linux]<br />
</code></p>
<h3>Step 8: Install RubyGems</h3>
<p>RubyGems is a package manager like aptitude that makes is trivial to add/update/delete resources that ruby (and Rails) will need. It&#8217;s also how you will install and update Rails. We are going to install RubyGems from source as the aptitude package is quite out-of-date. RubyGems is a self-updating application, and when installed from aptitude, aptitude will complain and you may accidentally downgrade RubyGems.</p>
<p><code># create a sources directory in your home<br />
mkdir ~/sources<br />
cd ~/sources</p>
<p>#download gem package, see <a href="http://rubyforge.org/projects/rubygems/">rubygems homepage</a> for the latest<br />
wget http://rubyforge.org/frs/download.php/38646/rubygems-1.2.0.tgz</p>
<p># decompress the files and setup rubygems<br />
tar xzvf rubygems-1.2.0.tgz<br />
cd  rubygems-1.2.0<br />
sudo ruby setup.rb</p>
<p># add a symlink<br />
sudo ln -s /usr/bin/gem1.8 /usr/bin/gem</p>
<p>#update rubygems<br />
sudo gem update --system<br />
sudo gem update<br />
</code></p>
<h3>Step 9: Install Ruby on Rails</h3>
<p>All this work, and we are finally here. Too bad installing Rails is so easy. Just this one line.</p>
<p><code>sudo gem install rails </code><br />
and a couple more gems you will probably need&#8230;<br />
<code># install the native (faster) mysql driver<br />
sudo gem install mysql</p>
<p># if you want native (faster) sqlite3 drivers, for production<br />
sudo apt-get install libsqlite3-dev<br />
sudo gem install sqlite3-ruby</code></p>
<p>You can install any more gems you may need at this time with &#8217;sudo gem install <em>package-name</em>&#8216;, but if you are using rails 2.1 or greater, you can now add rubygem requirements to your <em>environment.rb</em> file and use rake to automatically installed gem dependencies.</p>
<h3>Step 10: Install Phusion Passenger</h3>
<p>There are many ways to host a Rails application, but at this time, <a href="http://www.modrails.com">Phusion Passenger</a> gets the nod for the easiest to deploy and our experience has been rock-solid in reliability. These install steps are from the <a href="http://modrails.com/install.html">Passenger website installation instructions</a>:</p>
<p><code>sudo gem install passenger<br />
sudo apt-get install apache2-prefork-dev<br />
sudo passenger-install-apache2-module<br />
# and follow the instructions</p>
<p># after phusion installs, you will see instructions to edit your Apache configuration file<br />
#  to add lines to the end of the file<br />
sudo pico /etc/apache2/apache2.conf</p>
<p># add the lines given in the installation screen, because they can be different for each machine, I can't post the instructions here</p>
<p># restart apache webserver<br />
sudo /etc/init.d/apache2 restart<br />
</code></p>
<p>You will also be given a sample virtual host file to setup your Rails application. At this point you can copy an existing Rails app over to the new server, or follow along for a quick setup of a new Rails app.</p>
<h3>Step 11: Create a Rails Application (optional)</h3>
<p>We are going to create a very quick Rails application to test that our installation is working.</p>
<p><code>cd ~/<br />
rails tester<br />
script/generate scaffold Blog name:string content:text<br />
rake db:migrate RAILS_ENV=production</p>
<p># setup apache<br />
sudo a2dissite default  # we don't need this anymore<br />
sudo pico /etc/apache2/sites-available/tester</p>
<p>#enter the following in pico<br />
&lt;VirtualHost *:80&gt;<br />
  ServerName localhost<br />
  DocumentRoot /home/user_name/tester/public<br />
&lt;/VirtualHost&gt;</p>
<p># activate this site<br />
sudo a2ensite tester<br />
sudo /etc/init.d/apache2 restart<br />
</code></p>
<p>Now you can visit your site by going to http://address_of_server/ and you should see your rails application!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.spoolz.com/2008/07/30/ruby-on-rails-ubuntu-server-vm-with-vmplayer/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Ruby: Send Email Reminders from iCal Calendar</title>
		<link>http://blog.spoolz.com/2008/07/21/ruby-send-email-reminders-from-ical-calendar/</link>
		<comments>http://blog.spoolz.com/2008/07/21/ruby-send-email-reminders-from-ical-calendar/#comments</comments>
		<pubDate>Tue, 22 Jul 2008 01:34:07 +0000</pubDate>
		<dc:creator>Karl</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[erb]]></category>
		<category><![CDATA[icalendar]]></category>
		<category><![CDATA[yaml]]></category>

		<guid isPermaLink="false">http://blog.spoolz.com/?p=17</guid>
		<description><![CDATA[This is going to be long, so hunker down for a good read.
Problem: Our Cub Scout den leader sends email reminders to all the parent about upcoming events. I decided to setup a gCal (google calendar) will all the events so that other parents could just check the calendar as they wish, or subscribe to [...]]]></description>
			<content:encoded><![CDATA[<p>This is going to be long, so hunker down for a good read.</p>
<p><b>Problem:</b> Our Cub Scout den leader sends email reminders to all the parent about upcoming events. I decided to setup a gCal (google calendar) will all the events so that other parents could just check the calendar as they wish, or subscribe to the ical file to integrate with their own calendar. But several of the parents don&#8217;t have calendars (shame, shame) and everyone still liked the idea of receiving email reminders. So I decided to write a ruby script to email reminders automatically two days before the event.</p>
<p><b>Solution:</b> Ruby is a great language to handle this. Especially since there are gems to handle many of the functions we need. Some of the gems we will be using are as follows:</p>
<p><span id="more-17"></span></p>
<ul>
<li><a href="http://www.ruby-doc.org/stdlib/libdoc/open-uri/rdoc/index.html">open-uri</a>: to get the ical file via http</li>
<li><a href="http://www.ruby-doc.org/stdlib/libdoc/net/smtp/rdoc/index.html">net/smtp</a>: to send the email, you could use ActionMailer as well</li>
<li><a href="http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/index.html">erb</a>: email body is in a template.html.erb file for easy editing, erb processes the file</li>
<li><a href="http://www.ruby-doc.org/stdlib/libdoc/yaml/rdoc/index.html">yaml</a>: a list of sent notifications are logged in a yaml file</li>
<li><a href="http://icalendar.rubyforge.org/">icalendar</a>: the superb ical manipulation gem from Jeff Rose</li>
</ul>
<p>All you need to do is setup a cron job to run this script. I chose to run the script at 8pm every evening.</p>
<p>I&#8217;m going to break this script apart by methods for easier commenting. You can download the complete script file and templates to follow along. In the single script file is logging and some formatting methods that don&#8217;t really need explanation here.</p>
<p>The script all assembled with some nice logging: <a href='http://blog.spoolz.com/wp-content/uploads/2008/07/notification_script.rb'>notification_script.rb</a><br />
A sample email template file: <a href='http://blog.spoolz.com/wp-content/uploads/2008/07/mail_templatehtml.erb'>mail_template.html.erb</a><br />
A sample recipient groupt list: <a href='http://blog.spoolz.com/wp-content/uploads/2008/07/group_list.txt'>group_list.txt</a></p>
<h3>Setup and Requires</h3>
<p>First, you are going to need the icalendar gem (<a href="http://icalendar.rubyforge.org/">documentation</a>), which you can install with:</p>
<pre class="brush: ruby">
sudo gem install icalendar
</pre>
<p>For the beginning of our script, we&#8217;ll need a few other libraries to be required, and set a constant or two.</p>
<pre class="brush: ruby">
require &#039;rubygems&#039;
require &#039;open-uri&#039;
require &#039;icalendar&#039;
require &#039;date&#039;
require &#039;net/smtp&#039;
require &#039;erb&#039;
require &#039;yaml&#039;

ICAL_URL = &#039;http://www.google.com/calendar/ical...path_to_your_ical_file&#039;
FROM_EMAIL = &#039;your_email_address@domain.com&#039;
MAIL_TEMPLATE_FILE = &#039;mail_template.html.erb&#039;
SENT_NOTIFICATIONS_FILE = &#039;sent_notifications.yml&#039;
GROUP_LIST_FILE = &#039;group_list.txt&#039;
DAYS_BEFORE_TO_SEND = 2
</pre>
<p>All of these requires should already be installed in your standard ruby library. Following the requires are some constants you need to edit. The ICAL_URL constant is the url that you can look up from google calendars by going to your Calendar Settings, and selecting Calendar Details. You should see the ICAL (green) button that when you click, it shows you the url for the ical file of your calendar. Copy and paste this url into the ICAL_URL constant. You will also want to change the FROM_EMAIL to your email address, or the one you want notifications to be from.</p>
<p>The other constants are the names of the files that should be in the same directory as the script. You can rename them or change the paths as necessary.</p>
<h3>The Main Event</h3>
<p>I like to wrap my main events in a method called &#8216;init()&#8217; and place it near the top of the script file so that it is quick and easy to find. You don&#8217;t have to do this, but supporting methods will have to come <em>before</em> your code.</p>
<pre class="brush: ruby">
def init
  begin
  myFile = open(ICAL_URL).read

  cals = Icalendar.parse(myFile)
  cal = cals.first

  cal.events.each{ |e|
    time_diff = e.dtstart - DateTime.now
    if time_diff &lt; (DAYS_BEFORE_TO_SEND * 24 * 60 * 60) &amp;amp;amp;&amp;amp;amp; time_diff &gt; 0

      if notified?(e.uid)
        #log &#039;    notification previousy sent.&#039;

      else
        send_to = group_list
        msg = ERB.new(File.read( MAIL_TEMPLATE_FILE )).result( binding )

        send_email(&#039;Den 4 Notifications&#039;, &#039;your_email@domain.com&#039;, send_to, e.summary, msg)

        add_notification_to_list(e.uid)
      end
    end
    }

  rescue
    #log the error
  end
end
</pre>
<p>Pretty easy, huh? Let start breaking this down in greater detail:</p>
<h3>Step 1: Read the iCal File</h3>
<p>Read the contents of the ical file at the ICAL_URL location. Using the open-uri library, the content of the ical file is read into a string object.</p>
<h3>Step 2: Parse the iCal File with Icalendar</h3>
<p>The Icalendar gem first requires that we parse the ical file, so that it can create the representative &#8217;calendar&#8217; and &#8216;event&#8217; objects for reading. There is the potential of more than one calendar in the ics file. But in our case, we know there is only one, so we need to get that first &#8216;calendar&#8217; object.</p>
<h3>Step 3: Loop Through the Calendar Events</h3>
<p>We need to look at every calendar &#8216;event&#8217; object in the calendar so that we can look at the start date (e.dtstart) so see if it&#8217;s within the DAYS_BEFORE_TO_SEND.</p>
<h3>Step 4: Previous Notification Sent? Ready Email Template</h3>
<p>The &#8216;notified?&#8217; method will tell us if this event has received previous notification. The e.uid attribute is a unique identifier associated with every event (an event id, if you will). We check that e.uid against a list of saved uid&#8217;s.</p>
<p>Then we can read the MAIL_TEMPLATE_FILE and use erb to process the file, substituting the various object attributes (variables). This makes it easy to change the email template without editing our script file.</p>
<h3>Step 5: Send the Email Message</h3>
<p>A Couple of things happen here that we&#8217;ll discuss in the &#8217;send_email&#8217; method, but suffice it to say that this sends the email to all the addresses in the GROUP_LIST_FILE.</p>
<h3>Step 6: Add Notification to List</h3>
<p>We save a list of the event uids (e.uid) that have been notified so that we don&#8217;t send a notification again.</p>
<p><strong>Pretty spiffy, huh?</strong></p>
<p>Now lets show some of the supporting methods and discuss.</p>
<h3>Method: notified?</h3>
<p>This method reads the SENT_NOTIFICATIONS_FILE yaml file to see if the passed &#8216;uid&#8217; exists in the list of events with previous notification. The loop looks at each item in the &#8216;y_content&#8217; array to see if the &#8216;uid&#8217; is a match. If there is a match, return true (I like the explicitness of using return here). You can see how the yaml file is structured in the &#8216;add_notification_to_list&#8217; method.</p>
<pre class="brush: ruby">
def notified?(uid)
  if File.exist?( SENT_NOTIFICATIONS_FILE )
    File.open( SENT_NOTIFICATIONS_FILE ) { |yf|
      y_content = YAML.load( yf )

      if y_content.is_a? Array
        y_content.each{ |e| return true if e[:uid] == uid }
      end
    }
  end

  return false  #not found
end
</pre>
<h3>Method: group_list</h3>
<p>The GROUP_LIST_FILE is a text file with the address of whom we want to send the notification emails to, separated by a linefeed. You can change this to suit your needs, like comma or pipe separation. It returns the list of email addresses in an array.</p>
<p>If the GROUP_LIST_FILE does not exist or there is an error reading the file, a default email address is returned so that at least someone gets notified. I would normally not do it his way and let the rescue raise an error and halt the script.</p>
<pre class="brush: ruby">
def group_list
  begin
    IO.read( GROUP_LIST_FILE ).split(/\n/)
  rescue
    return Array[&#039;default_email@domain.com&#039;]
  end
end
</pre>
<h3>Method: send_email</h3>
<p>Here we get to use the net/smtp gem to send the email. I chose this because it has fairly low overhead and it actually pretty easy to use. I&#8217;m not sure you can use it to send attachments, but in our case, we are just sending HTML emails.</p>
<p>A <a href="http://blog.jayfields.com/2006/12/ruby-multiline-strings-here-doc-or.html">heredoc</a> is used to create the string for the message header. I&#8217;m not such a fan of heredoc, so this is my one and only time I&#8217;ll use it.</p>
<p>Notice that the &#8216;Content-Type: text/html&#8217; is set so that the receive recognizes this as an HTML email and not plain text. Use &#8216;Content-Type: text/plain&#8217; if you&#8217;re sending a text only email.</p>
<p>You will have to set your SMTP server setting were you see &#8216;mail.my_server.com&#8217;. For more information on this, see the <a href="http://www.ruby-doc.org/stdlib/libdoc/net/smtp/rdoc/index.html">NET::SMTP documentation</a>. Because there are many configurations for this, I didn&#8217;t place constants at the beginning of the script. The <a href="http://www.ruby-doc.org/stdlib/libdoc/net/smtp/rdoc/index.html">NET::SMTP docs</a> pretty much cover it.</p>
<p>I would have liked to send all the messages using BCC, but alas I could find no documentation in NET::SMTP supporting BCC. In my case, everyone know everyone else, so it&#8217;s no big whoop.</p>
<pre class="brush: ruby">
def send_email(from_alias, from, to_array, subject, message)
	msg = &lt;&lt;END_OF_MESSAGE
From: #{from_alias} &lt;#{from}&gt;
To: #{to_array.collect{ |item| &#039;&lt;&#039; + item + &#039;&gt;&#039; }.join(&#039;,&#039;)}
Subject: [CUB SCOUTS]#{subject}
Content-Type: text/html

#{message}
END_OF_MESSAGE

	Net::SMTP.start( &#039;mail.my_server.com&#039;, 25 ) do |smtp|
		smtp.send_message msg, from, to_array
	end
end
</pre>
<h3>Method: add_notification_to_list </h3>
<p>Here we add an event uid to a yaml file and timestamp it. I&#8217;m sure there are a million ways to do this, but I just wanted to play around reading/writing yaml files.</p>
<p>There is one thing I don&#8217;t like about this though&#8230; the entire yaml file is read in, the new event is added to the end, and the resulting yaml replaces the entire existing file. I could not find a reliable way to append a yaml object to an existing yaml file. Well, sort of, but it creates an new array object hash for each append, instead of having all events in one array of hashes. Yeah, yeah, I&#8217;m being picky.</p>
<pre class="brush: ruby">
def add_notification_to_list(uid)
  if File.exists?( SENT_NOTIFICATIONS_FILE )
    y_content = YAML.load( File.open( SENT_NOTIFICATIONS_FILE ) )
  end

  y_content = [] unless y_content.is_a?( Array )

  File.open( SENT_NOTIFICATIONS_FILE, &#039;w+&#039; ) { |yf|
    y_content.concat [ :date =&gt; Time.now, :uid =&gt; &quot;#{uid}&quot; ]
    YAML.dump( y_content, yf )
  }
end
</pre>
<h3>Put it All Together&#8230;</h3>
<p>The script all assembled with some nice logging: <a href='http://blog.spoolz.com/wp-content/uploads/2008/07/notification_script.rb'>notification_script.rb</a><br />
A sample email template file: <a href='http://blog.spoolz.com/wp-content/uploads/2008/07/mail_templatehtml.erb'>mail_template.html.erb</a><br />
A sample recipient groupt list: <a href='http://blog.spoolz.com/wp-content/uploads/2008/07/group_list.txt'>group_list.txt</a></p>
<p>All that&#8217;s left is to put all the files in a directory that has read/write access (for the log file and notification list file) and setup a cron job. Now you have automated notifications from your calendar.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.spoolz.com/2008/07/21/ruby-send-email-reminders-from-ical-calendar/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
