<?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>How they Discovered Something Worth Knowing</title>
	<atom:link href="http://www.silverchairsolutions.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.silverchairsolutions.com/blog</link>
	<description>reflections on life, technology and brownies</description>
	<lastBuildDate>Tue, 29 Sep 2009 19:09:44 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Running HTTPS in your Rails Development Environment</title>
		<link>http://www.silverchairsolutions.com/blog/2009/09/runnning-https-in-your-rails-development-environment/</link>
		<comments>http://www.silverchairsolutions.com/blog/2009/09/runnning-https-in-your-rails-development-environment/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 15:53:33 +0000</pubDate>
		<dc:creator>mhagedorn</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://www.silverchairsolutions.com/blog/?p=27</guid>
		<description><![CDATA[If you are building a rails application that requires SSL for parts of your site, you are probably going to use the SSL requirement plugin.   But that alone isn&#8217;t going to allow you to run your code in development.  You can easily see this after you enable the SSL Requirement plugin (suddenly [...]]]></description>
			<content:encoded><![CDATA[<p>If you are building a rails application that requires SSL for parts of your site, you are probably going to use the <a href="http://dev.rubyonrails.org/svn/rails/plugins/ssl_requirement/">SSL requirement plugin</a>.   But that alone isn&#8217;t going to allow you to run your code in development.  You can easily see this after you enable the SSL Requirement plugin (suddenly nothing will work).   Your single mongrel instance is going to need some help in order to be able process https requests!   I wanted a simple way to allow my rails development process to continue normally and still have https protected code.</p>

<p><span id="more-27"></span>
Its not hard to set this up (ok its a bit tedious), but as <a href="http://www.subelsky.com/2007/11/testing-rails-ssl-requirements-on-your.html">Mike Subelsky</a> noted in his blog post, its not really written up elsewhere in one compact recipe.  I wanted to take a slightly different approach than what Mike took, in that I wanted to disturb the default OSX install as little as possible.  Since OSX includes an apache webserver, the idea is that you have that webserver proxy all the SSL details and then pass off control to your development instance running on localhost:3000.   The built-in instance of apache can be turned on and off in OSX by going to the Sharing control panel in your System Preferences.   If you mark the checkbox named &#8220;Web Sharing&#8221; apache is on and running, and off if the checkbox is off.   You can verify this by turning it on then browsing to http://localhost, you should see an apache screen.</p>

<h1>Step 1 &#8211; Configuring SSL Encryption</h1>

<p>Note that this recipe is a condensed version of what is found <a href="http://developer.apple.com/internet/serverside/modssl.html">here</a>, but I have cut out all the commentary. You will be using terminal for all the rest of this.  Also I am using OSX Leopard
* Shut down your local apache server
either turn off web sharing or </p>

<pre><code>sudo apachectl stop
</code></pre>

<ul>
<li><p>Create a Working Directory</p>

<p>mkdir ~/Desktop/KeyGen; cd ~/Desktop/Keygen</p></li>
<li><p>Create the RSA private key</p>

<p>openssl genrsa -des3 -out server.key 1024</p></li>
</ul>

<p>use a passphrase here as directed (and remember it <img src='http://www.silverchairsolutions.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  )</p>

<ul>
<li><p>Create the CSR (Certificate Signing Request)</p>

<p>openssl req -new -key server.key -out server.csr </p></li>
</ul>

<p>This signing request you will sign yourself (for development only of course).  For this CSR enter &#8216;127.0.0.1&#8242; for the prompted &#8220;Common Name &#8211; i.e. for the appropriate server&#8221;</p>

<ul>
<li><p>Create a Certificate Authority (CA) to sign the key</p>

<pre><code>openssl genrsa -des3 -out ca.key 1024
</code></pre></li>
</ul>

<p>use a passphrase here again</p>

<ul>
<li><p>Create a self-signed CA certificate using the key you just made</p>

<p>openssl req -new -x509 -days 365 -key ca.key -out ca.crt</p></li>
</ul>

<p>in the &#8220;Common Name&#8221; field enter your name, because you are the dummy certificate authority and you are the one signing it.</p>

<ul>
<li><p>Download the latest mod_ssl distribution
It can be found <a href="http://www.modssl.org/">here</a>.  Look in the pkg.contrib subdirectory and copy the file sign.sh to your working directory. Then you have to make the file executable, and sign the csr.</p>

<p>chmod +x sign.sh ;./sign.sh server.csr</p></li>
</ul>

<p>Enter &#8216;yes&#8217; for all the prompts, and you will have a directory full of files, representing the signed csr.</p>

<ul>
<li><p>Put the signed files where apache can use them</p>

<p>sudo mkdir /etc/apache2/ssl.key</p></li>
</ul>

<p>Move all of the contents of your working directory to the ssl.key directory you just made.</p>

<pre><code>sudo cp -r * /etc/apache2/ssl.key/
</code></pre>

<ul>
<li><p>Remove the passphrase from the server key (DONT DO THIS FOR A PRODUCTION SYSTEM)</p>

<pre><code>cd /etc/httpd/ssl.key
sudo cp server.key server.key.original
sudo openssl rsa -in server.key.original -out server.key
</code></pre></li>
</ul>

<h1>Step 2 &#8211; Modify the Apache config files</h1>

<ul>
<li><p>First, back up the existing apache config file for safety</p>

<p>cd /etc/apache2
sudo cp httpd.conf httpd.conf.backup</p></li>
<li><p>Then use your favorite editor to enable the appropriate LoadModule statements.   (you are going to have to use sudo (&#8217;sudo vi&#8217;) to open this file in order to save it).  Search for a line that looks like this:</p>

<p>LoadModule ssl<em>module libexec/apache2/mod</em>ssl.so</p></li>
</ul>

<p>and make sure that the # at the beginning of the line is not there (i.e. the comment indication), if it is there remove it.  Likewise remove # from this line a bit farther down</p>

<pre><code>Include /private/etc/apache2/extra/httpd-vhosts.conf
</code></pre>

<p>and this&#8230;</p>

<pre><code>Include /private/etc/apache2/extra/httpd-ssl.conf
</code></pre>

<ul>
<li><p>Back up your extra/httpd-ssl.conf</p>

<p>sudo cp httpd-ssl.conf httpd-ssl.conf.original</p></li>
<li><p>Comment out the following line by putting a # at the beginning of it (we are putting this setting in the httpd-vhosts.conf file)</p>

<p>Listen 443</p></li>
<li><p>Remove the Virtual Host</p></li>
</ul>

<p>Then remove all the lines starting at</p>

<pre><code>    &lt;VirtualHost _default_:443&gt;
</code></pre>

<p>and ending at</p>

<pre><code>    &lt;/VirtualHost&gt; 
</code></pre>

<p>We are going to define all our virtual host stuff in the httpd-vhosts.conf file, so its not needed here.</p>

<ul>
<li><p>Back up your extra/httpd-vhosts.conf and edit it</p>

<p>sudo cp httpd-vhosts.conf httpd-vhosts.conf.original</p></li>
</ul>

<p>I pretty much deleted everything in my vhosts file and replaced it with the following content</p>

<pre><code>Listen 443

SSLCertificateFile /etc/apache2/ssl.key/server.crt
SSLCertificateKeyFile /etc/apache2/ssl.key/server.key

CustomLog logs/ssl_request_log  "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

&lt;VirtualHost *:80&gt;
 ServerName localhost
 ServerAlias 127.0.0.1

 ProxyPass / http://localhost:3000/
 ProxyPassReverse / http://localhost:3000
 ProxyPreserveHost on
&lt;/VirtualHost&gt;

&lt;VirtualHost *:443&gt;
 SSLEngine On
 ServerName localhost
 ServerAlias 127.0.0.1

 ProxyPass / http://localhost:3000/
 ProxyPassReverse / http://localhost:3000
 ProxyPreserveHost on
 RequestHeader set X_FORWARDED_PROTO 'https'
&lt;/VirtualHost&gt;
</code></pre>

<p>And thats it.  Go to your Sharing control panel and turn on Web Sharing.  You should see https requests being forwarded correctly to your rails application (assuming that its listening on the default mongrel port of 3000).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.silverchairsolutions.com/blog/2009/09/runnning-https-in-your-rails-development-environment/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Announcing the migrate_war Rails plugin</title>
		<link>http://www.silverchairsolutions.com/blog/2008/04/announcing-the-migrate_war-rails-plugin/</link>
		<comments>http://www.silverchairsolutions.com/blog/2008/04/announcing-the-migrate_war-rails-plugin/#comments</comments>
		<pubDate>Thu, 17 Apr 2008 16:32:00 +0000</pubDate>
		<dc:creator>mhagedorn</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://www.silverchairsolutions.com/blog/?p=26</guid>
		<description><![CDATA[The MigrateWar Rails plugin makes it easy to create database schema on deployment machines when you deploy via JRuby/War Files.  This is especially helpful on Windows machines, where you cannot use Capistrano easily. 

Capistrano is a powerful deployment tool that is considered &#8217;state of the practice&#8217; by anyone deploying Rails applications to Unixy type [...]]]></description>
			<content:encoded><![CDATA[<p>The MigrateWar Rails plugin makes it easy to create database schema on deployment machines when you deploy via JRuby/War Files.  This is especially helpful on Windows machines, where you cannot use Capistrano easily. </p>

<p>Capistrano is a powerful deployment tool that is considered &#8217;state of the practice&#8217; by anyone deploying Rails applications to Unixy type systems.  But what about if you need some of that same Capistrano fu on a windows server.   Can it be done?   In my case I really needed a way to build my
database schema on the deployment target as soon as the application was deployed (cap deploy with migrations basically).   This isnt such an 
easy thing to do as I found.    I was going to deploy via JRuby/Goldspike in a War file format (the standard java deployment package), so I dusted off my arcane Java knowledge and came up with a solution to load the schema.rb file as soon as the war file loads.  Read on for details.</p>

<p><span id="more-26"></span></p>

<p>The trick here, was that I needed the &#8220;migrate to current&#8221; process to run only once, when the Rails application loads.  When you deploy the web application via the Goldspike Plugin, you end up with a pretty standard Java Web Application  WAR file (i.e. Web ARchive).   WAR files have a very well defined set of hooks for startup and teardown, which of course would directly correspond to the startup of the Rails application that we are deploying inside of that WAR file.  So the basic trick, is to leverage the startup hook of the WAR file (In Javaland this is called a Context) and run the appropriate logic for creating database schema on the deployment box.    You could of course do arbitrary other things as well, but thats a talk for another time.</p>

<p>We want to do this in such a way that we are writing a minimum of Java code, and pushing most of the work of doing this off to Ruby.  The first thing we have to do is create the Java class which runs when the Context loads (i.e. the Rails application).   This is done by creating a ServletContextListener, an interface in Java.   Here is an excerpt of the class I wrote (showing only the important bits)</p>

<p>`  </p>

<pre><code>    public void contextInitialized(ServletContextEvent event) {
  try {
      final ServletContext context = event.getServletContext();
      // create the pool
      initiallizeJrubyEnvironment(context);

      //this is defined in the web.xml
      commandFile = context.getInitParameter("command-file");


      System.out.println("Entering: MigratorContentListener.contextIntialized \n");

      thread = new Thread(new Runnable() {

          public void run() {
              try {
                  // wait for a little while before starting the task
                  // this allow the app server to start serving requests before initializing all tasks
                  Thread.sleep(100);


                  runOnce(context);
                  System.out.println("Exiting: MigratorContentListener.contextIntialized \n");
              } catch (InterruptedException e) {
                  // break out of loop
              } catch (Exception e) {
                  context.log("Could not start " + commandFile, e);
              }
          }
      });
      thread.start();
  } catch (ServletException ex) {
      Logger.getLogger(MigratorContextListener.class.getName()).log(Level.SEVERE, null, ex);
  }}'
</code></pre>

<p>&#8216;<br />
    private void runOnce(ServletContext context) throws Exception {</p>

<pre><code>    try {
        String rootDir = context.getRealPath("");

        Ruby runtime = null;
        try {

            String script = readFileAsString(rootDir + "/" + commandFile);
            context.log("executing "+script);
            runtime = (Ruby) getRuntimePool().borrowObject();
            runtimeApi.eval(runtime,"ENV['RAILS_ROOT'] = '" + rootDir + "'");
            runtimeApi.eval(runtime, script);
            getRuntimePool().returnObject(runtime);
        } catch (Exception e) {
           context.log("Could not execute: " + commandFile, e);
            getRuntimePool().invalidateObject(runtime);
          context.log(commandFile + " returning JRuby runtime to pool and will restart in 15 minutes.");
            try {
                Thread.sleep(FIFTEEN_MINUTES_IN_MILLIS);
            } catch (InterruptedException ex) {
            // can't do much here ...
            }
        }


    } catch (Exception e) {
        e.printStackTrace();
        context.log("Could not execute: " + commandFile, e);
    }
}`
</code></pre>

<p>The J2EE application server will call the contextInitiallized method shown above when the WAR file loads.  In the 4th line of that method, notice that I get the name of the ruby file to run, its passed in via a parameter defined in the web.xml file.   More on that later.    Basically this class executes the &#8220;runOnce&#8221; method one time, in a separate thread, as soon as the context loads.   Really all the runOnce method does is pass the name of the method to run to the Ruby runtime that has been set up  via the magic of JRuby.   </p>

<p>In order to get this file to get loaded by the Application Server, you need to make two entries in the web.xml file.   The first one, which tells it to attach a listener to the Context, looks like this  </p>

<p><code>&lt;listener&gt;
   &lt;listener-class&gt;org.jruby.webapp.MigratorContextListener&lt;/listener-class&gt;
 &lt;/listener&gt;</code></p>

<p>where the MigratorContextListener is the Java class that contains the logic listed above.  The second entry that you need to put into the web.xml file is what the ruby file is named that you want executed.   Here is that entry  </p>

<p><code>&lt;context-param&gt;
    &lt;param-name&gt;command-file&lt;/param-name&gt;
    &lt;param-value&gt;migrator.rb&lt;/param-value&gt;
    &lt;description&gt;Run this file to execute an initial migration (for deployment to new platforms)&lt;/description&gt;
&lt;/context-param&gt;</code></p>

<p>The migrator.rb file, the one that gets executed on startup (and found in the root of the application), looks like this  </p>

<p><code>load('db/schema.rb')</code></p>

<p>Once this executes, the production database indicated in the database.yml will get the schema.rb file applied to it.  It would have been much cooler to actually run a migration, but by the time you deploy to production, your schema has probably settled down anyway, so applying the schema.rb file is probably sufficient.  I guess the bigger point is, you can do arbitrary things at install time with this.</p>

<p>I bundled all of this up into a plugin called &#8220;migrate_war&#8221;, one of the things this plugin includes is a jar file which contains the ContextListener, you have to tell the GoldSpike plugin about this jar file so that it includes it in the WAR file it generates.   To do this edit the config/war.rb file and add this to the end:  </p>

<p><code>include_library 'migrator-rails' , '0.9'</code></p>

<p>When you install the plugin, it will copy that jar to lib/java and the include_library command will find it there and pull it into the generate WAR file.</p>

<p>Once you have installed the plugin and made the include_library addition shown above, go ahead and generate your WAR file using Goldspike.</p>

<p>After that finishes you can edit the web.xml file found in WEB-INF/web.xml (Goldspike generates the WEB-INF and everything below it) with the xml edits shown above (for the listener, and the command-file).  Then you need to run it again to generate the WAR file with the modified web.xml included (if the WEB-INF directory already exists the Goldspike plugin won&#8217;t clobber this directory unless you tell it to, so its cool to edit these files before generating again, Goldspike will use whats in WEB-INF).</p>

<p>You can install the plugin by entering  </p>

<p><code>script/plugin install http://svn.silverchairsolutions.com/migrate_war/</code>. </p>

<p>Hope this helps someone!</p>

<p>Update:  Its important to note that this will apply the schema.rb file directly to your database.  This will blow away the schema contained within (and any data found there).  So if you need to save the data, you should export it then reimport it after the schema gets built.  It would be much cooler if migrations were run on this.  Anyone care to try?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.silverchairsolutions.com/blog/2008/04/announcing-the-migrate_war-rails-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby on Rails Contractor:   I am Available! (One of the Advanced Rails Recipes Book contributors )</title>
		<link>http://www.silverchairsolutions.com/blog/2008/04/ruby-on-rails-contractor-i-am-available-one-of-the-advanced-rails-recipes-book-contributors/</link>
		<comments>http://www.silverchairsolutions.com/blog/2008/04/ruby-on-rails-contractor-i-am-available-one-of-the-advanced-rails-recipes-book-contributors/#comments</comments>
		<pubDate>Sun, 13 Apr 2008 01:51:28 +0000</pubDate>
		<dc:creator>mhagedorn</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.silverchairsolutions.com/blog/?p=25</guid>
		<description><![CDATA[I just posted this to craigslist:

I am web developer who specializes in Ruby on Rails contracts and works remotely from my home office. Currently looking for new projects, I&#8217;m open to conversations about new contract possibilities. My company is Silverchair Solutions, an agile web development consultancy.  I have over 13 years of web development [...]]]></description>
			<content:encoded><![CDATA[<p>I just posted this to craigslist:</p>

<p>I am web developer who specializes in Ruby on Rails contracts and works remotely from my home office. Currently looking for new projects, I&#8217;m open to conversations about new contract possibilities. My company is Silverchair Solutions, an agile web development consultancy.  I have over 13 years of web development experience 
and two and a half years of Rails experience.  Recently some of my work was published in the Advanced Rails Recipes book (Pragmatic Programmers &#8211; see the wizard chapter!).  I am a former Oracle DBA and am very comfortable designing databases as well as configuring linux/mac os servers in support of my web applications.</p>

<p>To learn more about me, view my Linkedin profile <a href="http://www.linkedin.com/pub/0/51/b39">here:</a></p>

<p><a href="http://www.workingwithrails.com/person/8989-mike-hagedorn">Working with Rails Profile</a></p>

<p>If you have a project that you think I may be able to help you with, please send me an email with a short description of what it is you need done and we will chat!</p>

<p>Thanks,
Mike</p>
]]></content:encoded>
			<wfw:commentRss>http://www.silverchairsolutions.com/blog/2008/04/ruby-on-rails-contractor-i-am-available-one-of-the-advanced-rails-recipes-book-contributors/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I&#8217;m an Author!</title>
		<link>http://www.silverchairsolutions.com/blog/2008/04/im-an-author/</link>
		<comments>http://www.silverchairsolutions.com/blog/2008/04/im-an-author/#comments</comments>
		<pubDate>Sat, 12 Apr 2008 14:35:05 +0000</pubDate>
		<dc:creator>mhagedorn</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://www.silverchairsolutions.com/blog/?p=24</guid>
		<description><![CDATA[Ok its been awhile since this occurred, but I would be remiss if I didn&#8217;t mention that I have been included as one of the authors of the Pragmatic Studio&#8217;s Advanced Rails Recipes Book.   I contributed a chapter on creating Wizards.   You can check it out here.  Basically I leveraged [...]]]></description>
			<content:encoded><![CDATA[<p>Ok its been awhile since this occurred, but I would be remiss if I didn&#8217;t mention that I have been included as one of the authors of the Pragmatic Studio&#8217;s Advanced Rails Recipes Book.   I contributed a chapter on creating Wizards.   You can check it out <a href="http://www.pragprog.com/titles/fr_arr" title="Advanced Rails Recipes">here</a>.  Basically I leveraged acts<em>as</em>state_machine to pull this off.  Check it out!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.silverchairsolutions.com/blog/2008/04/im-an-author/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using your website url as your OpenID</title>
		<link>http://www.silverchairsolutions.com/blog/2008/03/using-your-website-url-as-your-openid/</link>
		<comments>http://www.silverchairsolutions.com/blog/2008/03/using-your-website-url-as-your-openid/#comments</comments>
		<pubDate>Wed, 12 Mar 2008 14:22:28 +0000</pubDate>
		<dc:creator>mhagedorn</dc:creator>
				<category><![CDATA[OpenId]]></category>

		<guid isPermaLink="false">http://www.silverchairsolutions.com/blog/?p=23</guid>
		<description><![CDATA[I have an OpenId, I have found it useful.   But frankly its just another thing that I have to remember.  Somthing that I can&#8217;t forget is my website url.  What if you could set up some kind of cool forwarding that allows me to use my website url as my OpenID? [...]]]></description>
			<content:encoded><![CDATA[<p>I have an OpenId, I have found it useful.   But frankly its just another thing that I have to remember.  Somthing that I can&#8217;t forget is my website url.  What if you could set up some kind of cool forwarding that allows me to use my website url as my OpenID?   Well&#8230; you can.  Actually if you just have a blog and not a full blown website, this will work too.   </p>

<p>Add some entries to the head section of the index page of your website </p>

<hr />

<pre><code>`&lt;link rel="openid.server" href="http://www.myopenid.com/server" /&gt;
&lt;link rel="openid.delegate" href="http://your.real.openid.com/" /&gt;'
</code></pre>

<p>Where, the openid.server is the url of your provider, and the openid.delegate is your real openid identity.</p>

<p>This trick will work with any resource you have access to on the internet, i.e. anything where you could add information to the head portion of your index page.   Many thanks to <a href="www.duncandavidson.com">Duncan Davidson</a> for this tip</p>
]]></content:encoded>
			<wfw:commentRss>http://www.silverchairsolutions.com/blog/2008/03/using-your-website-url-as-your-openid/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automating Cocoa Deployments with Sparkle and Xcode</title>
		<link>http://www.silverchairsolutions.com/blog/2008/03/automating-cocoa-deployments-with-sparkle-and-xcode/</link>
		<comments>http://www.silverchairsolutions.com/blog/2008/03/automating-cocoa-deployments-with-sparkle-and-xcode/#comments</comments>
		<pubDate>Fri, 07 Mar 2008 16:40:12 +0000</pubDate>
		<dc:creator>mhagedorn</dc:creator>
				<category><![CDATA[Cocoa]]></category>

		<guid isPermaLink="false">http://www.silverchairsolutions.com/blog/?p=22</guid>
		<description><![CDATA[For those of us who live in the rails world, fantastic tools like Capistrano have made deployment drop-dead simple.   And since I do some Cocoa work I found myself wanting some of that same  capistrano-esqe love in my Cocoa deployments.   The Sparkle framework handles most of this for you, but [...]]]></description>
			<content:encoded><![CDATA[<p>For those of us who live in the rails world, fantastic tools like <a href=""www.capify.org"">Capistrano</a> have made deployment drop-dead simple.   And since I do some Cocoa work I found myself wanting some of that same  capistrano-esqe love in my Cocoa deployments.   The <a href=""http://sparkle.andymatuschak.org/"">Sparkle</a> framework handles most of this for you, but in its vanilla implementation requires you to hand code some descriptor files and this seemed problematic to me.   So I have cooked up an Xcode based recipe which allows me to do push button deploys and let Sparkle handle the updating part.</p>

<p><span id="more-22"></span></p>

<p>I got the germ of the idea for this one from <a href=""http://duncandavidson.com/"">Duncan Davidson&#8217;s</a> blog post (which sadly is no longer available due to a server crash) of last fall where he too was longing for something like capistrano to automatically handle pushing up code updates.   I will condense what I remember from his post.   </p>

<p>At its heart, this approach starts by recognizing that Xcode allows you to keep project specific settings (kind of like environment variables) in a separate file called an .xcconfig file.   For us this file will contain the version number of the code that we are going to deploy.   In this technique this value will be manually editing.   Everytime we want to do a deploy, edit the xcconfig file, then do a deployment.   The deployed code will show up on the client with the version number you specified in the .xcconfig file.</p>

<h1>Create the Xcode Config File</h1>

<p>In your cocoa project, add a new file to the project (File -> New File) and select  Xcode/Configuration Settings File.   Call it whatever works for you.   Open the file up in Xcode and add this single line to it (or more if you are using xcconfig for other things too <img src='http://www.silverchairsolutions.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  )</p>

<p><code>WIDGET_VERSION = 0.99</code></p>

<p>(Replace WIDGET with whatever the name is of your application, its up to you, you are merely defining a variable here that you will use in your Plist ).</p>

<p>The next step is to make sure XCode uses the xcconfig file that we just created.  To do this, select the project icon in the outline view of Xcode and hit command-I.  This will bring up the project information for your project.   Navigate to the build tab on this window, and at the bottom of this tab you should see &#8220;Based on:&#8221;, with a drop down to pick an xcconfig file to base this build on.   Since we are going to control the version number through the xcconfig, we want to select the xcconfig file that holds our version number here.</p>

<h1>Modify the PList file to utilize the setting from the .xcconfig file</h1>

<p>Lets now edit Info.plist file to make use of the version number.  Edit the plist so that it looks like this (I have only listed the appropriate lines, leave the lines alone)</p>

<p><code>&lt;key&gt;CFBundleVersion&lt;/key&gt;
 &lt;string&gt;${WIDGET_VERSION}&lt;/string&gt;</code></p>

<p>Save this and lets move on&#8230;</p>

<h1>Create a new build target which does the deploy</h1>

<p>Add a new target to your XCode project, and call it Deploy.  Drag your build product under this target as well.  This step will make sure that building the application will happen before deploying it (it makes it a dependency).   Add a new build phase to your Deploy target, add a build phase that is of type Run Script.  &#8221; Add -> New Run Script Build Phase&#8221;.  Edit this run script build phase to look like this:</p>

<pre><code>if [ "Release" != "$CONFIGURATION" ]; then
    echo 'error: Package creation only works for Release builds'
    exit -1
fi

./ruby_deploy.rb $WIDGET_VERSION $CONFIGURATION_BUILD_DIR`
</code></pre>

<h1>Create the Ruby File Which Does the Packaging</h1>

<p>In our run script phase we just wrote, we turn around and execute a ruby script called <code>ruby_deploy</code>.  This is a custom script that we are going to create right now.  Go ahead and add a new empty file to your project, and save it as ruby_deploy.rb.   Here is a suggested starting place that I use.  Feel free to modify it as needed for what you are doing</p>

<pre><code>#!/usr/bin/env ruby
#
#  ruby_deploy.rb
#  widget
#
#  Created by Mike Hagedorn on 12/1/07.
#  Copyright (c) 2007 Silverchair Solutions. All rights reserved.
#


require 'rss/1.0'
require 'rss/2.0'
require 'open-uri'
require 'rss'

require 'net/http'


#put your application name here
APPLICATION_NAME="widget"
#put your user name here
USERNAME="user"
#specify the appropriate server and directories here
SCP_DESTINATION="yourserver.com:the_directory_where_you_want_it_on_your_webserver/apps/#{APPLICATION_NAME}"
SCP_SOURCE="/tmp"


version = ARGV[0]
build_dir = ARGV[1]
proper_name = APPLICATION_NAME.capitalize
package = "#{proper_name}_#{version}.zip"
notes = "#{APPLICATION_NAME}_#{version}.html"
puts build_dir
`zip -r /tmp/#{package} \"#{build_dir}/PhonoscopeDialer.app\"`
url_base = "http://yourserver.com/apps/#{APPLICATION_NAME}"
dist_dir = url_base

content = ""
# raw content of rss feed will be loaded here
open("#{url_base}/appcast.xml") do |s|
    content = s.read
end
rss = RSS::Parser.parse(content, false)

package_url = "#{url_base}/#{package}"
zip_ctime = File.ctime("#{SCP_SOURCE}/#{package}")
zip_size = File.size("#{SCP_SOURCE}/#{package}")
pub_date = zip_ctime.localtime.strftime("%a, %d %b %Y %T %z")

last_item = rss.items.last

latest_version = last_item.title.split.last
if version.to_f &lt;= latest_version.to_f
    puts "version not updated, returning"
    exit -1
end


source = "#{SCP_SOURCE}/#{package}"
dest = "#{USERNAME}@#{SCP_DESTINATION}/#{package}"
`scp \"#{source}\" \"#{dest}\"`

content_new = RSS::Maker.make("2.0") do |m|
    m.channel.title = "Your Application Log"
    m.channel.link = "#{url_base}/appcast.xml"
    m.channel.description = "Most recent changes with links to updates."
    m.channel.language = "en"
    rss.items.each do |item|
        m.items.new_item do |newitem|
            newitem.title = item.title
            newitem.link = item.link
            newitem.description = item.description  
            newitem.enclosure.url = item.enclosure.url  
            newitem.enclosure.type = item.enclosure.type
            newitem.enclosure.length = item.enclosure.length
            newitem.date = item.date
        end
    end
#add the new one
m.items.new_item do |appendedItem|
    appendedItem.title = "Your Application Version #{version}"
    appendedItem.description = "#{url_base}/#{APPLICATION_NAME}_#{version}.html"
    appendedItem.enclosure.url = "#{package_url}"
    appendedItem.enclosure.type = 'application/octet-stream'
    appendedItem.enclosure.length = "#{zip_size}"
    appendedItem.date = pub_date        
end


end

puts content_new
File.open("#{SCP_SOURCE}/appcast.xml","w") do |f|
    f.write(content_new.to_s)
end


source = "#{SCP_SOURCE}/appcast.xml"
dest = "#{USERNAME}@#{SCP_DESTINATION}/appcast.xml"
`scp \"#{source}\" \"#{dest}\"`

source = "#{build_dir}/#{notes}"

dest = "#{USERNAME}@#{SCP_DESTINATION}/#{notes}"
`scp \"#{source}\" \"#{dest}\"`
</code></pre>

<p>Lets step through this script.  The first thing to do (and this will be custom to your application) is to set up  values for a specific server on the internet where your application will be stored.   The variables set up here for the location of the appcast need to match the SUFeedURL entry in your Plist file.   You would have had to set that up when you integrated Sparkle.  Heres an example that would match the ruby file listed above.</p>

<p><code>&lt;key&gt;SUFeedURL&lt;/key&gt;
&lt;string&gt;http://www.yourserver.com/apps/widget/appcast.xml&lt;/string&gt;</code></p>

<p>The next thing that is done is to create the archive (zip file) of the built application.  That&#8217;s why building the application is a prerequisite for the deploy step, you want to make sure you have code there to actually zip up.   After you zip up the file, you store it in the <code>/tmp</code> directory. </p>

<p>Now we need to update the appcast.xml file, this is the RSS feed that your application will check to see if there is a more recent drop of the application available. The basic workflow is, go out to the internet, grab the appcast.xml feed (the xml), parse the file to find the last revision number, if the current revision is equal to the last revision, exit and do nothing.  If however the revision number is greater (this should usually be the case) then go ahead and copy the zipped up code out to the server using scp, secure copy.   Then you need to create an RSS item for the new current revision (the update) and append it to the collection of items in the RSS feed.   Then you simply copy back the new and improved appcast.xml file out to your server.  Here is a simple example of an appcast file, to get this process started you need to copy this file out to your server first (so that it can be fetched and parsed)</p>

<pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt; 
    &lt;rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle"&gt; 
    &lt;channel&gt; 
        &lt;title&gt;Your Application Log&lt;/title&gt; 
        &lt;link&gt;http://www.yourserver.com/apps/widget/appcast.xml&lt;/link&gt; 
        &lt;description&gt;Most recent changes with links to updates.&lt;/description&gt; 
        &lt;language&gt;en&lt;/language&gt; 
        &lt;item&gt; 
            &lt;title&gt;Version 0.9&lt;/title&gt; 
            &lt;description&gt;http://www.yourserver.com/apps/widget/widget_0.9.html&lt;/description&gt; 
            &lt;pubDate&gt;Fri, 30 Nov 2007 19:20:11 +0000&lt;/pubDate&gt; 
            &lt;enclosure url="http://www.yourserver.com/apps/widget/widget_0.9.zip" length="1600000" type="application/octet-stream"/&gt; 
        &lt;/item&gt; 
    &lt;/channel&gt; 
    &lt;/rss&gt; 
</code></pre>

<p>`</p>

<p>Another step here that is important to the workflow is to add a release note to each drop.  This is an html file that is displayed when the update is loading.  The naming convention is appname_version.html.   Here&#8217;s a simple example of that</p>

<pre><code>&lt;h2&gt;Notes on version 1.02&lt;/h2&gt;
&lt;ul&gt;
    &lt;li&gt;First Sparkle Release&lt;/li&gt;
&lt;/ul&gt;`
</code></pre>

<h1>Your Deployment Workflow</h1>

<p>Now that you have all this, how do you use it?   First do all your coding, testing, etc for your next release.  When you are ready to push out some changes, first create the html file listing your changes and add it to your project (so that the script can find it to copy it out to your deployment server). Use the naming convention listed above.  Then update your xcconfig file with the appropriate release number.  Then select the Deploy target and build.   That&#8217;s it.    Isn&#8217;t that cool?
`</p>
]]></content:encoded>
			<wfw:commentRss>http://www.silverchairsolutions.com/blog/2008/03/automating-cocoa-deployments-with-sparkle-and-xcode/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>State Transition Diagrams for acts_as_state_machine</title>
		<link>http://www.silverchairsolutions.com/blog/2008/03/state-transition-diagrams-for-acts_as_state_machine/</link>
		<comments>http://www.silverchairsolutions.com/blog/2008/03/state-transition-diagrams-for-acts_as_state_machine/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 22:31:49 +0000</pubDate>
		<dc:creator>mhagedorn</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://www.silverchairsolutions.com/blog/?p=21</guid>
		<description><![CDATA[Lately I have been using the wonderful acts_as_state_machine plugin for lots of cool stuff in my rails applications.   The problem that I have run into though, is visualizing the state transitions that I have created.  Typically, when I first learned about state machines back in Electrical Engineering days, we drew cool diagrams [...]]]></description>
			<content:encoded><![CDATA[<p>Lately I have been using the wonderful <code>acts_as_state_machine</code> plugin for lots of cool stuff in my rails applications.   The problem that I have run into though, is visualizing the state transitions that I have created.  Typically, when I first learned about state machines back in Electrical Engineering days, we drew cool diagrams with bubbles to represent the states and arrows to show the state transitions (a.k.a state transition diagrams).  I have found these to be very helpful.   But I wanted to a way to automatically create these.</p>

<p><span id="more-21"></span></p>

<p>My first problem was, how do I dynamically create graphs?   This was solved when I found out about this:
<a href="http://www.graphviz.org" title="graphviz">Graphviz</a>, an open source graph visualization language that many software packages understand.   There are stand-alone graph readers available as well as tools like OmniGraffle for the mac which can read this format.  We will create our diagrams in this format (.dot).  </p>

<p>My solution was inspired by Dave Thomas and his <em>annotate_models</em> plugin.   I created a plugin that is triggered as a rake task, i.e. <code>rake annotate_states</code>   I used Dave&#8217;s code to guide me on how to step through all the model classes, then I added additional logic to filter out all model classes that didnt use acts<em>as</em>state_machine.   I then introspected on the remaining list and got a list of states and transitions so that I could build the diagram.</p>

<p>You can install the plugin in the usual way, navigate to the root of your application and type <code>script/plugin install http://svn.silverchairsolutions.com/annotate_states</code>.   </p>

<p>After installing the plugin (and checking that it lists as a rake task by typing rake -T) you can create the .dot files for your application by typing <code>rake annotate_states</code>.   Each model file in your application that uses <code>acts_as_state_machine</code> should produce a state transition diagram in the root of your application.</p>

<p>Hope you enjoy it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.silverchairsolutions.com/blog/2008/03/state-transition-diagrams-for-acts_as_state_machine/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Remote Access to your mac via Back To My Mac (Leopard)</title>
		<link>http://www.silverchairsolutions.com/blog/2007/11/remote-access-to-your-mac-via-back-to-my-mac-leopard/</link>
		<comments>http://www.silverchairsolutions.com/blog/2007/11/remote-access-to-your-mac-via-back-to-my-mac-leopard/#comments</comments>
		<pubDate>Thu, 01 Nov 2007 15:26:10 +0000</pubDate>
		<dc:creator>mhagedorn</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.silverchairsolutions.com/blog/?p=20</guid>
		<description><![CDATA[Ok I know there are a million ways to do this &#8220;by hand&#8221;, but if you have a .mac membership this is for free basically&#8230; automatic remote access to your machines on the internet via your .Mac account.  If you look carefully under the .Mac settings for Leopard, there is a &#8220;Back To My [...]]]></description>
			<content:encoded><![CDATA[<p>Ok I know there are a million ways to do this &#8220;by hand&#8221;, but if you have a .mac membership this is for free basically&#8230; automatic remote access to your machines on the internet via your .Mac account.  If you look carefully under the .Mac settings for Leopard, there is a &#8220;Back To My Mac&#8221; option.  This basically wraps up all of the things like dyndns, etc into one easy to use package.  Its really cool!  Now I just need to have two machines running Leopard.  I wonder if I can hack Tiger to use this?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.silverchairsolutions.com/blog/2007/11/remote-access-to-your-mac-via-back-to-my-mac-leopard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OSX Leopard, RSpec Autotest Growl/growlnotify Workaround</title>
		<link>http://www.silverchairsolutions.com/blog/2007/10/osx-leopard-rspec-autotest-growlgrowlnotify-workaround-2/</link>
		<comments>http://www.silverchairsolutions.com/blog/2007/10/osx-leopard-rspec-autotest-growlgrowlnotify-workaround-2/#comments</comments>
		<pubDate>Wed, 31 Oct 2007 15:06:21 +0000</pubDate>
		<dc:creator>mhagedorn</dc:creator>
				<category><![CDATA[Rspec]]></category>

		<guid isPermaLink="false">http://www.silverchairsolutions.com/blog/?p=19</guid>
		<description><![CDATA[Upon loading up the new release of OSX 10.5 (Leopard), I was very frustrated to find that Growl notifications no longer work when using
Autotest.  Apparently growlnotify, the command line app which makes the magic happen, isn&#8217;t compatible.   Read on to see how I got this work


It turns out that there is another [...]]]></description>
			<content:encoded><![CDATA[<p>Upon loading up the new release of OSX 10.5 (Leopard), I was very frustrated to find that Growl notifications no longer work when using<br />
Autotest.  Apparently growlnotify, the command line app which makes the magic happen, isn&#8217;t compatible.   Read on to see how I got this work</p>

<p><p><span id="more-19"></span></p>
<p>It turns out that there is another way to get notifications into Growl other than the the (broken) growlnotify.   That technique is to use Applescript.<br />
Applescript allows you to do all sorts of neat things to applications in OSX but it is an arcane and hard to understand beast (at least in my<br />
opinion &#8211; feel free to flame me <img src='http://www.silverchairsolutions.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ).  Based on a sample from the Growl website I was able to cobble together a working solution which<br />
restores all the growlnotify goodness we have come to expect from Autotest.  The first thing is to write the Applescript which talks to Growl.</p>
<p>Here is what I came up with (as modified from the Growl website)</p>
<p> &#8212;  growlNotify.applescript<br />
    &#8211;<br />
    &#8212;  Created by Mike Hagedorn on 2007-10-31.<br />
    &#8212;  Copyright (c) 2007 Silverchair Solutions. All rights reserved. http://www.silverchairsolutions.com<br />
    &#8212; based on script from the growl website<br />
    &#8212; works around the fact that growlnotify doesnt work on leopard</p>
<p> &#8212; pass in like osascript  growlNotify.applescript <title> <message> <image><br />
    on run argv<br />
        set rspec<em>title to item 1 of argv<br />
        set rspec</em>message to item 2 of argv<br />
        set rspec<em>image to item 3 of argv</p>
<p>     tell application &#8220;GrowlHelperApp&#8221;<br />
         &#8212; Make a list of all the notification types<br />
         &#8212; that this script will ever send:<br />
         set the allNotificationsList to ¬<br />
          {&#8221;RSpec Notification&#8221; }</p>
<p>      &#8212; Make a list of the notifications<br />
         &#8212; that will be enabled by default.<br />
         &#8212; Those not enabled by default can be enabled later<br />
         &#8212; in the &#8216;Applications&#8217; tab of the growl prefpane.<br />
         set the enabledNotificationsList to ¬<br />
          {&#8221;RSpec Notification&#8221;}</p>
<p>      &#8212; Register our script with growl.<br />
         &#8212; You can optionally (as here) set a default icon<br />
         &#8212; for this script&#8217;s notifications.<br />
         register as application &#8220;Growl-RSpec AppleScript Notifications&#8221; ¬<br />
           all notifications allNotificationsList ¬<br />
           default notifications enabledNotificationsList ¬<br />
           icon of application &#8220;Script Editor&#8221;</p>
<p>      &#8212; Send a Notification&#8230;<br />
         notify with name &#8220;RSpec Notification&#8221; ¬<br />
           title rspec</em>title ¬<br />
           description rspec<em>message ¬<br />
           application name &#8220;Growl-RSpec AppleScript Notifications&#8221; ¬<br />
           image from location  rspec</em>image</p>
<p>     end tell</p>
<p> end run</p>
<p>Put this file somewhere where you can find it (I used ~/Library/Scripts/growlNotify.applescript) then modify the .autotest file you have in your home directory<br />
to not call growlnotify, but the new method you just crafted (i.e. the applescript).  Here is what mine looks like</p>
<p> #<br />
    #  .autotest<br />
    #  Autotest Growl Notifications for Rspec and Test::Unit<br />
    #<br />
    #  Created by Rein Henrichs on 2007-09-12.<br />
    #  Modified by Mike Hagedorn (www.silverchairsolutions.com) to use osascript to work around Leopard issues<br />
    #<br />
    #  Copyright 2007 Rein Henrichs.<br />
    #  http://pastie.caboo.se/96573/download<br />
    # </p>
<p> require &#8216;logger&#8217;<br />
    logfile = File.join(File.dirname(<strong>FILE</strong>), &#8216;.autotest.log&#8217;)<br />
    $logger = Logger.new(logfile)</p>
<p> module Autotest::Growl<br />
      Autotest.add<em>hook :ran</em>command do |at|<br />
        input = Input.new( at.results )<br />
        Growler.display<em>notification( input )<br />
      end<br />
    end  </p>
<p> class String<br />
      def remove</em>color<em>codes!<br />
        self.gsub!(/\e&#91;\d+m/,&#8221;)<br />
        self.strip!<br />
      end<br />
    end</p>
<p> class Growler<br />
      class &lt;&lt; self<br />
        def display</em>notification( input )<br />
          growler = RspecGrowler if input.from<em>rspec?<br />
          growler = TestUnitGrowler if input.from</em>test<em>unit?<br />
          growler.display</em>notification( input.result<em>line )<br />
        rescue => e<br />
          $logger.fatal e<br />
          notify</em>system<em>error( &#8220;Unexpected Error&#8221;, &#8220;Please check your ~/.autotest.log and report anything strange to reinh@reinh.com&#8221; )<br />
        end</p>
<p>     def notify(title, msg, img, pri=0, stick=&#8221;" )<br />
          #system &#8220;growlnotify -n autotest &#8211;image #{img} -p #{pri} -m #{msg.inspect} #{title} #{stick}&#8221;<br />
          system &#8220;osascript ~/Library/Scripts/growlNotify.applescript &#8216;#{title}&#8217; &#8216;#{msg.inspect}&#8217;  &#8216;#{img}&#8217;&#8221;<br />
        end</p>
<p>     def notify</em>system<em>error( title = &#8220;System Error&#8221;, err = &#8220;&#8221;)<br />
          Growler.notify( title, err, &#8216;~/Library/autotest/rails</em>fail.png&#8217;)<br />
        end<br />
      end<br />
    end</p>
<p> class Input<br />
      def initialize(input)<br />
        @input = input<br />
      end</p>
<p>   def empty?; @input.empty?; end</p>
<p>   # TODO: Make these work<br />
      def failing?; end<br />
      def passing?; end<br />
      def error?; end</p>
<p>   def from<em>rspec?; !!rspec</em>result<em>line || empty?; end<br />
      def from</em>test<em>unit?; !!test</em>unit<em>result</em>line; end<br />
      def rspec<em>result</em>line; @input.grep( /\d+\sexample/ ).first; end<br />
      def test<em>unit</em>result<em>line; @input.grep( /\d+\sassertion/ ).first; end<br />
      def result</em>line<br />
        @line ||= case<br />
          when from<em>rspec? then rspec</em>result<em>line<br />
          when from</em>test<em>unit? then test</em>unit<em>result</em>line<br />
          else nil<br />
          end<br />
        @line.remove<em>color</em>codes! if @line<br />
      end<br />
    end</p>
<p> class AutoGrowler &lt; Growler<br />
      class &lt;&lt; self<br />
        def notify<em>failure(input)<br />
          notify( &#8220;Tests Failed&#8221;, input, &#8216;~/Library/autotest/rails</em>fail.png&#8217;, 2 )<br />
        end<br />
        def notify<em>success(input)<br />
          notify( &#8220;Tests Passed&#8221;, input, &#8216;~/Library/autotest/rails</em>ok.png&#8217;, 0 )<br />
        end<br />
      end<br />
    end</p>
<p> class RspecGrowler &lt; AutoGrowler<br />
      class &lt;&lt; self<br />
        def notify<em>pending(input)<br />
          notify( &#8220;Tests Pending&#8221;, input, &#8216;~/Library/autotest/pending.png&#8217;, 1 )<br />
        end</p>
<p>     def notify</em>error<br />
          notify( &#8220;Syntax Error&#8221;, &#8220;It looks like there was a syntax error. Check your autotest results.&#8221;, &#8216;~/Library/autotest/rails<em>fail.png&#8217;)<br />
        end</p>
<p>     def display</em>notification(input)</p>
<p>       notify<em>error and return unless input<br />
          # TODO: replace with some object oriented goodness. elsif FTL!<br />
          examples, failures, pending = input.split(&#8221;, &#8220;)<br />
          if failures.to</em>i > 0<br />
            notify<em>failure input<br />
          elsif pending.to</em>i > 0<br />
            notify<em>pending input<br />
          else<br />
            notify</em>success input<br />
          end<br />
        end<br />
      end<br />
    end</p>
<p> class TestUnitGrowler &lt; AutoGrowler<br />
      class &lt;&lt; self<br />
        def notify<em>error(input)<br />
          notify( &#8220;Tests Errored&#8221;, input, &#8216;~/Library/autotest/rails</em>fail.png&#8217;, 2 )<br />
        end<br />
        def display<em>notification( input )</p>
<p>       # TODO: replace with some object oriented goodness. elsif FTL!<br />
          tests, assertions, failures, errors = input.split(&#8221;, &#8220;)<br />
          if errors.to</em>i > 0<br />
            notify<em>error input<br />
          elsif failures.to</em>i > 0<br />
            notify<em>failure input<br />
          else<br />
            notify</em>success input<br />
          end<br />
        end<br />
      end<br />
    end</p>
<p>Notice that the change here is a small one, only on line 44, reference the commented out growlnotify.  This is working great for me.  Hope this helps<br />
you!</p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.silverchairsolutions.com/blog/2007/10/osx-leopard-rspec-autotest-growlgrowlnotify-workaround-2/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>ActiveScaffold &amp; Streamlined Woes</title>
		<link>http://www.silverchairsolutions.com/blog/2007/10/activescaffold-streamlined-woes/</link>
		<comments>http://www.silverchairsolutions.com/blog/2007/10/activescaffold-streamlined-woes/#comments</comments>
		<pubDate>Mon, 08 Oct 2007 15:34:09 +0000</pubDate>
		<dc:creator>mhagedorn</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://www.silverchairsolutions.com/blog/?p=17</guid>
		<description><![CDATA[Found an interesting gotcha while trying out some of the new &#8220;User Interface in a Can&#8221; frameworks.   If you use the new hasmany :through style declaration (rather than the old way hasandbelongsto_many)
for modeling your many to many relationships in ActiveRecord, then that relationship cannot be editable in these frameworks.  What happens is [...]]]></description>
			<content:encoded><![CDATA[<p>Found an interesting gotcha while trying out some of the new &#8220;User Interface in a Can&#8221; frameworks.   If you use the new has<em>many :through style declaration (rather than the old way has</em>and<em>belongs</em>to_many)
for modeling your many to many relationships in ActiveRecord, then that relationship cannot be editable in these frameworks.  What happens is that a relationship
is inferred, but since that relationship is read-only, a gui is generated which cannot edit that relationship.  Which in non-geek speak means <em>WORTHLESS</em>.
Since I was on a tight time budget on a project, I had to do something, so I am in the process of converting back to HABTM, which both frameworks
happily use.  I haven&#8217;t had a moment to grok why this is.  But something about the existence of the :through class messes up introspecting the relationships.
I am hoping this isn&#8217;t too much of a limitation, because I like overall the GUI&#8217;s that are produced.   Furthermore in my work at least I haven&#8217;t had to utilize
the power of a full-fledged join model in the middle, so I am hoping that this wont mess me up too much.</p>

<p>Has anyone else run into this?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.silverchairsolutions.com/blog/2007/10/activescaffold-streamlined-woes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
