Rails-Footnotes Resurrected For Rails 3

Posted by Rick DeNatale Wed, 18 May 2011 18:30:00 GMT
A few weeks ago I noticed that there was some recent maintenance activity on the old rails-footnotes gem. I used to use this years ago. Among other things it manipulates the backtrace you get when a rails app raises an exception in development mode so that each line in the backtrace is actually a link which will bring up your favorite editor to the appropriate line of the sourcefile. It also adds links to get to the source for the controller, views, etc for the page you are displaying in development mode. I was disappointed that the backtrace links didn't seem to work with Rails 3. So I forked the code on github, and fixed that. This morning I noticed that the backtrace code had been removed from the official code, but there were some other fixes. So I merged the official branch back to my forked version, and it seems to be working. Getting this to work with Rails 3 required a bit of ahem duck-punching of the Rails::BacktraceCleaner, and there arent any tests for this, but it seems to be working. My version is in github in a repo owned by my employer Scimed Solutions , and I've sent a pull request If you're using Rails 3, you might want to check it out, and provide feedback

Making RSpec, Rake, and Bundler play well together

Posted by Rick DeNatale Fri, 25 Jun 2010 11:45:00 GMT

I'm working a project which uses RSpec, Bundler, and Rails 2.3.4.

The team has been struggling with the changes in gem management with Bundler. The "Old School" rails way to configure gems for different rails environments is to conditionally execute gem.configure based on the rails environment. Then use the rake:gems:install task to gem install the gems, one for each environment.

Bundler does things a bit differently. It uses groups to segregate gems by environment, so you name the gems needed for the test environment in a :test group. When you run bundle install, it installs all of the gems for all of the groups (unless you opt out of some groups. It uses the groups at run time, to selectively expose only gems applicable to the current environment.

This cause problems for things like the spec rake task. If you run

rake spec

without explicitly setting the Rails environment.

The way the spec rake task works is that it depends on a rails provided rake task called :environment, which 'boots' the rails environment, then the spec_helper file which each spec whould require, sets ENV['RAILS_ENV'] to 'test' if it's not already set, then it requires needed gem code, like 'spec/rails'.

In the old school approach this works, since those gems are installed and visible. With bundler, it fails since they won't be exposed, since the bundler environment got set up using the development environment, so gems in the :test group aren't available.

In an attempt to fix this, other members on the team were mixing things up, doing things like putting conditional tests of the rails environment in the Gemfile, and then running the bundle command with different overrides of the RAILS_ENV environment variable.

But that way lies madness.

This morning I worked out a solution which involves deferring setting up the bundle environment.

  1. I needed to keep the spec task from running the environment task. The project was already using a variation of override_rake_task, so I added an override in a task within the lib directory:
          override_task :spec do
            Rake::Task["spec:original"].execute
          end
        
  2. The next step was to bootstrap the rails environment in spec_helper. To do this I started it with:
          ENV["RAILS_ENV"] ||= 'test'
    
          RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
          environment_path = File.expand_path(File.join(RAILS_ROOT, 'config', 'environment'))
          require(environment_path)
            require 'spec/rails'
            #... any other needed requires
        

    It's crucial to expand the path which ensures that the same string is used whenever the environment file is required. Before I did that I was having problems with the environment being required a second time, presumably for the second spec. If you have any code which patches anything using alias_method_chain, or a similar technique, loading that code a second time can cause infinite loops which can be mystifying.

So this seems to be working. I'll try to update if I find anything else, but in the meantime I hope some folks find it useful.


Ruby Version Management: Multiruby and RVM

Posted by Rick DeNatale Wed, 02 Sep 2009 21:11:00 GMT

Many Rubyists find the need from time to time to run multiple versions of Ruby. If you are developing open-source code, it's a good idea to try to maintain compatibility with all three of the main versions of Ruby current in use, 1.8.6, 1.8.7 and 1.9

There have been some tools for this for a while now. A lot of you probably already know about multiruby, and many may be aware of a new gem called rvm for Ruby Version Manager.

These two are useful for different purposes. Multiruby excels for testing ruby code against different versions, while rvm is great for quickly switching rubies so that you can play with one or the other. I think of RVM as a set of hand tools, and multiruby as a power tool workshop

They complement each other, but I've had a few bumps getting them to work together, hence this article.

Multiruby

One tool which helps do this is the multiruby suite of tools which are part of Ryan Davis' ZenTest gem. There are three tools in this suite:

multiruby_setup
which allows you to install and maintain a collection of Ruby versions. The various versions are installed in a subdirectory of .multiruby in your home directory
multiruby
which runs each of the installed ruby commands with the same arguments.
multigem
which uses multiruby to run the gem command in order to install gems in the right place for each of the ruby versions under that .multiruby directory.

For my RiCal gem, I have some rake tasks which run the rspec suite for the gem using multiruby, so I can be sure it still works with "the big three" before I publish a new version. To enable this I submitted a patch to RSpec to let you tell an instance of RSpecRakeSpecTask where to find the 'ruby' command. David incorporated this several releases of RSpec ago. This lets me have this in a rake file:

  multiruby_path = `which multiruby`.chomp
  if multiruby_path.length > 0 && Spec::Rake::SpecTask.instance_methods.include?("ruby_cmd")
    namespace :multi do
      desc "Run all specs with multiruby and ActiveSupport"
      Spec::Rake::SpecTask.new(:with_active_support) do |t|
        t.spec_opts = ['--options', "spec/spec.opts"]
        t.spec_files = FileList['spec/**/*_spec.rb']
        t.ruby_cmd = "#{multiruby_path}"
        t.verbose = true
        t.ruby_opts << "-r #{File.join(File.dirname(__FILE__), *%w[gem_loader load_active_support])}"
      end

      desc "Run all specs multiruby and the tzinfo gem"
      Spec::Rake::SpecTask.new(:with_tzinfo_gem) do |t|
        t.spec_opts = ['--options', "spec/spec.opts"]
        t.spec_files = FileList['spec/**/*_spec.rb']
        t.ruby_cmd = "#{multiruby_path}"
        t.verbose = true
        t.ruby_opts << "-r #{File.join(File.dirname(__FILE__), *%w[gem_loader load_tzinfo_gem])}"
      end
    end

    desc "run all specs under multiruby with ActiveSupport and also with the tzinfo gem"
    task :multi => [:"spec:multi:with_active_support", :"spec:multi:with_tzinfo_gem"]
  end  

I've got three tasks here because RiCal works with either the tzinfo gem OR activesupport from Rails, and I want to test each combination of gems and ruby versions.

RVM

Like multiruby, rvm lets you set up and use multiple versions of ruby. As I said above the difference here is that while multiruby runs them all together, rvm is for when you want to pick one to use for a while.

The rvm command is used to:

  • install a ruby implementation specifying one of ruby for MRI ruby, ree for Ruby Enterprise Edition a version of MRI patched for use with passenger (a/k/a mod-rails) or jruby surprisingly enough for JRuby and optionally the specific version and even patch level.
  • pick which ruby to use by using "rvm use which", where which is one of the above or default for the standard ruby installation for your system.

as well as other management functions.

The rvm gem is actually a thin ruby wrapper around some bash scripts. The way rvm works is to set up shell environment variables when you use "rvm use" so you get the right ruby executables and environment, and there lies the rub.

Who's got the Gem

Now did I tell you that I decided to add rvm to my arsenal right after I upgraded my MacBook to run Snow Leopard?

Because of this I had to rebuild a lot of my ruby development tool chain. I decided just to 'fault in' things that I found to be missing when I found that they were missing. A lot of those things were gems. So I'd run my various ruby projects, and when I found a missing gem, I'd install it.

So I ran my normal spec tasks against RiCal, and installed the missing gems. When I got those working, I ran the multiruby taks, and found that the tzinfo gem was missing. This wasn't a surprise since multiruby (like rvm) maintains a separate set of gems for each implementation. It was just a matter of "multigem install tzinfo" and move on to the next step. Wrong!

Multiruby reported that it had installed the tzinfo gem for each of the installed multiruby implementations, but when I ran the rake task again, no joy, same thing. Running "multigem list" revealed that there were no gems for any of the multiruby installs!

After a bit of head-scratching, I realized that rvm was setting GEM_HOME so that the gem command would know where to look for and install gems, and this was confusing multigem, which simply runs the gem command with ruby which ends up installing gems relative to the implementations installation directory. But GEM_HOME overrides this, so multigem was just reinstalling the gem three times in whatever directory rvm wanted them.

The Workaround

What's working for me is to use the bash command "unset GEM_HOME" before running multigem. This removes the variable entirely, and multigem goes back to working "normally." It's not ideal but it works.


Rails Deployment Options

Posted by Rick DeNatale Wed, 05 Aug 2009 13:53:00 GMT

Chris Wanstrath (a.k.a. defunkt) just wrote an article on the github blog about how he cut the time to deploy github itself from fifteen minutes to fourteen seconds.

The starting point was the observation that since the standard Capistrano deployment tasks treat the code repository as a black box plugin, they aren't optimized. They treat git repositories pretty much the same as they do subversion repos.

In a search for a better way, Chris takes on a tour of the various Capistrano alternatives, Vlad the Deployer, Heroku's Rush, and finally Fabric a deployment framework written in Python, before coming full circle back to Capistrano and refactoring the deploy recipes, then rewriting the tasks to setup, update and rollback the code on the server using more "gitty" techniques.

Another thing which slowed the old deploy down was having a separate cap task to make each symlink needed on the server. Each cap task has some overhead, which Chris eliminated by making a single task which made all of the symlinks

The last change was moving the task of minimizing JavaScript and CSS from the machine running cap, where it was repeated for each server, to the servers themselves.

This is a great article, with lots of food for thought on how to use Cap and Git.


Silly Sinatra Application

Posted by Rick DeNatale Mon, 15 Jun 2009 03:46:00 GMT
Strangersinthenight
require 'rubygems'
require 'sinatra' 

def be
  "do, be, do, be, do"
end 

get '/strangers' do
   be do 
       be do
       end
   end
end
The thought occurred to me during Glenn Vanderberg's presentation on Sinatra at RubyRX a few months back.

Ri_Cal is Now On RubyForge

Posted by Rick DeNatale Tue, 26 May 2009 21:34:00 GMT

After a few weeks of maturation on github, setting up a bug tracker, and a google group for project discussions, the bug reports died down to the point where I felt comfortable putting a more "official" release out on rubyforge.

Thanks to my most active 'beta-testers', Adam Williams who really drove the calendar generation DSL, and Paul Scott-Murphy, and Bruno Duyé gave a much needed workout to occurrence enumeration.

With folks from Australia and France providing input, it felt a bit like the old OTI days


An Observation of How Rack is Affecting Rails

Posted by Rick DeNatale Fri, 08 May 2009 12:28:00 GMT

This started out with a question on the RSpec group about why debugger invocations in Cucumber steps seemed to be ignored.

Now, I didn't know the answer to that, but I did have a bit of related knowledge since one of my contributions to RSpec was adding the --debugger/-u option to the spec command as an analog to the same option in the script/server command in Rails. As far as I know that option hasn't been added to Cucumber.

Which led me to refreshing myself on how Rails implements that option in order to help answer the Cucumber question. So I brought up the rails gem in textmate on the latest version of Rails, and had a minor epiphany.

Under the Hood of the script/server --debugger Option

In Rails you can put debugger calls in your code which will cause a debugger breakpoint if you are running with the --debug option, but do nothing (actually it writes an info level entry to the log ) if you aren't.

The latter is pretty easy, during initialization, ActiveSupport asks Kernel if it responds to :debugger, and if not defines the method to do the log.

The other part involves script/server running this code when it starts up if -u or --debugger was one of the command line options:

  begin
    require_library_or_gem 'ruby-debug'
    Debugger.start
    Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
    puts "=> Debugger enabled"
  rescue Exception
    puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
    exit
  end

And the rspec command does pretty much the same thing since David picked up my contribution a few releases ago.

Rails 2.2 vs Rails 2.3

My epiphany came when I looked at Rails 2.3.1, and didn't have as much of a deja-vu as I expected. The difference is how that code to conditionally install and start the debugger gets executed.

In Rails 2.2, script/server looks at the first argument to determine whether to run mongrel, lighty, thin, or webrick. If that's not specified it goes through some sniff tests to infer which to run.

It then requires a specific server based script to actually run the server. The mongrel and webrick scripts support the debugger option and run the load code if it is specified.

Rails 2.3.1 does things a bit differently. The script/server program parse the options, then loads the debugger with this snippet of code:

app = Rack::Builder.new {
  use Rails::Rack::LogTailer unless options[:detach]
  use Rails::Rack::Debugger if options[:debugger]
  map map_path do
    use Rails::Rack::Static 
    run inner_app
  end
}.to_app

So the debugger is turned on by inserting a rack middleware, what does this look like?

module Rails
  module Rack
    class Debugger
      def initialize(app)
        @app = app

        require_library_or_gem 'ruby-debug'
        ::Debugger.start
        ::Debugger.settings[:autoeval] = true if ::Debugger.respond_to?(:settings)
        puts "=> Debugger enabled"
      rescue Exception
        puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
        exit
      end

      def call(env)
        @app.call(env)
      end
    end
  end
end

The code in the initialize method does give me deja-vu!

This is an interesting approach. It's consistent with Rails move to improved configurability using Rack. There's a slight overhead (1 method call per request) due to the passthrough, but that's insignificant in the overall scheme of things, particularly since it's only inserted when you are running with the debugger.


Ri_Cal Test Flight

Posted by Rick DeNatale Tue, 05 May 2009 16:33:00 GMT

Well, "a day or two" turned out to be a little more like a week, and the official release is still a bit in the future, but I've just published an unofficial version of ri_cal on github.

I've been working with Adam who is using github for a Rails app. He's been feeding me bugs to fix and features to add. Most of the work in the past week has been on developing the "DSL" for creating calendars and events programatically. There are a few loose ends to tie up but if you are adventurous, you might want to play with the library. There will likely be some api changes before the initial release.

When I'm ready to make the "official" release, I'll publish it to RubyForge as well as to git hub, and the version will be bumped to 0.x.0 once I've decided what x should be.

RiCal represents a considerable effort over the past several months. I hope someone besides Adam finds it useful.


You Get What You Pay For

Posted by Rick DeNatale Wed, 08 Apr 2009 21:02:00 GMT

Well, that’s the saying. One thing is for sure. You can’t expect to get what you don’t pay for.

I got an IM from a buddy this afternoon looking for a second opinion on a Rails application. Someone had paid for 100 hours of work (I don’t know at what rate), for a Rails project which wasn’t progressing to his liking. He’d asked my buddy to give an opinion of what had been done, and I was asked to have a look as well.

I only spent about a half hour or so looking at the code, since I was doing this as a courtesy. I spend quite a bit of pro-bono time helping others by writing here and contributing on public fora, but I’ve got my limits.

The executive summary: I wasn’t impressed.

This was a completely blind sampling. I have no idea who the consultant was who wrote this app, nor even the identity of the client who had funded it.

I noticed that there was both a spec and a stories directory in the project a good sign. Looking closer though the specs all seemed to have been generated automatically by the restful_authentication plugin, same thing for the stories.

And the tests were the standard useless stub tests generated by the Rails model/controller generators.

There was some very suspect code in some of the controllers I looked at, one was creating a model in the new action. Normally the new action instantiates an unsaved model instance for use by an edit/creation form, leaving the actual creation of the model in the database to the create action after the form is posted.

The Application controller had some strange looking code, which looked like it might be boilerplate from somewhere. When I googled for a snippet from the code, it looks like it came from somebody’s rails 2.3 template for generating a new rails app using shoulda.

So we have an app which can’t seem to decide which testing framework to use and then not really use any of them to any effect.

Now I know that shoulda, rspec and test::unit can be used in combination by a sophisticated developer, but I don’t think that’s what was going on here.

I poked around in a few models. I found one which really flummoxed me. The model purported to be representing a currency exchange rate for a particular currency on a particular date. The model had a class method average which took a currency and a date range as arguments. Now from the name, I’d expect that this would maybe calculate the average rate for instances for that currency between the first and last dates of the range. Lacking any tests/specs I’ll assume that’s what it would do.

What did it do?

def self.average(currency, date_range)
     first = find(:first, :conditions => ["currency = ? AND issued_on = ?", currency, date_range[0].to_date])
     first ||= find(:first, :conditions => ["currency = ?", currency] , :order => "issued_on"
     last = find(:first, :conditions => ["currency = ? AND issued_on = ?", currency, date_range[1].to_date])
     first ||= find(:first, :conditions => ["currency = ?", currency] , :order => "issued_on ASC"

     median(first.rate, last.rate)
end

protected
def median(a, b)
    (a + b) / 2
end

See anything strange here? Actually I see several.

  1. To find the first it looks for an instance for the currency which happened exactly on the starting date. If it doesn’t find one then it finds the first instance for that currency in the database. I would have expected to find the first instance on or after the starting date, which could have been done with a single find call with the right condition.
  1. Then to find the last it does what looks like a simple variant of the code to find the first, but is it a variant, instead of finding the last instance for the currency in the database rather than the first it’s going to again find the first. He wanted :order => “issued_on DESC”.
  1. What kind of average is being computed here anyway? Average is a generic term, normally we take it to denote the mean, which is the summation of a series of values divided by the number of elements in the series. We’re not doing that here, since we look at only two elements. Now the method being called is median, which is another type of average. You get the medium by sorting the series and picking either the middle element if the series has an odd number of elements, or the mean of the two middle elements. But that’s certainly not what this median method is doing.

Having specs or tests would have helped this guy both think through what he was trying to do, and to realize that it wasn’t working.

So to me it looks like the client had paid for some guy generating a rails app from some templates and plugins and then floundering around with no real idea of how to understand, let alone achieve, the goals of the application.

Like I said in the beginning, it’s not really that you get what you pay for, more like you sometimes get what you pay for. Since I don’t know the rate the client was charged, I don’t know whether he got what he paid for by hiring someone deservedly cheap, or just didn’t get what he paid for.

It’s always a shame when customers don’t get what they pay for, but in the current economy, it’s a real shame when a client burns money hiring someone on the cheap or without real credentials instead of paying someone who might at first look more expensive but would be a bargain in comparison in terms of value for money.


typo-5-1-with-capistrano-deploy-to-passenger-on-ubuntu-8-10-a-debriefing

Posted by Rick DeNatale Wed, 25 Mar 2009 19:12:00 GMT

Yesterday, I wrote about the crash project to resurrect this blog after a hardware failure. I'm now running it on an upgraded version of Typo (5.2 instead of 4.1), using Passenger on Ubuntu 8.10 (instead of a cobbled up stack of Apache, Pen, and Mongrel::Cluster on Ubuntu Dapper), and deployed from my MacBook using Capistrano with git as the source repository. I've been wanting to do a lot of this for a while, but never seemed to have the time. The crash gave me the motivation, and the necessity.

This article is to let me capture what I can remember while it's still fairly fresh in my memory, and hopefully provide help to others with similar goals.

Installing Passenger on Ubuntu 8.10

A bit of help from my friend google, led me to this how-to which I followed. I'm not entirely happy with the approach, since it installs Ruby using the debian package, and I generally prefer to install it from source. I also thought that it installed Rubygems from a package, but looking at it now it seems to have installed it from source, but installed in in /usr/bin which may not be the wisest place on a debian system, it really should be in /usr/local/bin or somewhere else that dpkg/apt-get doesn't muck with. I might need to straighten that out.

I had to hack his scripts a bit as well. They assume that the current directory is on the path, which is something I don't like to do, so I went through and added './' where necessary.

Finally, his script for upgrading to enterprise Ruby for improved performance didn't work, so that's a job for later.

I posted a few comments on the article about this, but as of now they are waiting for moderation.

Typo Upgrade

For those who haven't used it typo comes a a gem which provides a typo command, you use it to either install typo

typo install typo_dir

Either installs the latest version of typo, which is really just a rails app, in typo_dir, or upgrade an existng version.

One of the first things the upgrade does is to backup the database to a yml file. For a blog like mine with a lot of content, this took forever. As I sat there waiting, it occurred to me that I already had a mysql backup, which I'd already used to recreate the database, so I killed the upgrade and hacked the rails-app-installer gem (which typo uses) to skip the backup.

The next hurdle was a gem version problem. I got to the point where the upgrade script was trying to migrate the database, but Rake was failing

	Migrating Typo's database to newest release
	rake aborted!
	RubyGem version error: actionpack(1.13.3 not = 1.13.6)

This was particularly strange since Typo 5.2 runs on Rails 2.2. Somebody was loading the wrong version of rails, and then complaining about the wrong version of actionpack. And the 1.13.6 version of the actionpack gem doesn't seem to be around anymore, probably left behind when Rails moved to github.

So I asked on the typo mailing list, and my former co-worker Ben Burdick gave me the solution:

	sudo gem install datanoise-actionwebservice --source http://gems.github.com

This got me up to the point where I could run the blog on the MacBook. I used the very nice Passenger pane, you just drag the folder containing your rails project into the pane, and restart, and your app is running! Since I wanted to urls to match up. I told passenger pane to use a url of talklikeaduck.denhaven2.com instead of something.local, and put an entry into /etc/hosts to point that name to local host.

Once I was there, it was a matter of recreating the articles which had been lost since the last backup. Mark Imbriacco emailed me what he had cached for each article in his RSS reader. It turned out to be a pretty simple job of cutting and pasting, and telling Typo to publish the articles on their original dates which could be determined by the permalink urls. I didn't worry about the exact time.

I then did a mysqldump of the database, shipped it over to the server with scp, and recreated the database on the server.

Capistrano Deployment

Now the task was setting up Capistrano and having it get the code from git. For the time being I set up a git repository in my home directory on the server, and pushed the code to it from the MacBook over ssh.

The next step was to allow the apache user (which is www-data on debian based systems) to access the repo. This was a matter of generating a public/private key pair in the www-data users home directory, adding the public key part in the .ssh/authorized_keys file in MY home directory, and a

	sudo su - www-data
	ssh rick@localhost
	# answer yes to the prompt to add the host being connected to
	exit

I then upgraded my capistrano gem and capified my typo project. Then I edited the config/deploy.rb based on a couple of blog posts and some trial and error.

  set :application, "talklikeaduck" 
  set :repository, "ssh://rick@aaa.bbb.ccc.ddd/home/rick/git/tlad.git"
  set :scm, :git
  set :branch, "master"
  set :deploy_via, :remote_cache
  set :user, "www-data"
  set :runner, "www-data"
  set :deploy_to, "/var/www/rails/#{application}"

  role :app, "aaa.bbb.ccc.ddd"
  role :web, "aaa.bbb.ccc.ddd"
  role :db,  "aaa.bbb.ccc.ddd", :primary => true

  namespace :deploy do
    desc "Restarting mod_rails with restart.txt"
    task :restart, :roles => :app, :except => { :no_release => true } do
      run "touch #{current_path}/tmp/restart.txt"
    end

    [:start, :stop].each do |t|
      desc "#{t} task is a no-op with mod_rails"
      task t, :roles => :app do ; end
    end
  end

  desc "Link in the production database.yml" 
  task :after_update_code do
    run "ln -nfs #{deploy_to}/#{shared_dir}/config/database.yml #{release_path}/config/database.yml" 
  end

Note that I've replaced the lan address of the server with aaa.bbb.ccc.ddd, it probably wouldn't be a security exposure to show the real address behind the nat, but paranoia is paranoia. Normally I'd use a local dns server name, but I haven't gotten around to setting that back up.

Getting this working was a matter of trying cap deploy:check until I ironed out permissions issues, usually by sshing into the server creating files using sudo, then chowning them to www-data.www-data, since www-data doesn't have sudo privileges.

Then I worked on getting cap deploy:cold to work. More sshing, mkdiring, and chowning to set up the current, releases and shared subdirectories. I'd scratched my head a bit about what to do with config/database.yml which I'd gitignored as usual. Ben pointed me to a blog article which added a post setup task to upload it to the shared directory, but it turned out to be easier to just do it via scp and ssh.

If I recall correctly, the next hurdle was familiar, cap:deploy cold was failing for the same reasons as on the Mac, the gem version problem killing Rake. The solution here was to rake gems:push, git a

	rake gems:unpack
	git add vendor/gems
	git commit
	git push origin
	cap deploy:cold

Now I ran into a problem because I'd missed a bit of code in the deploy.rb from the article I was using a model. It was this piece:

[:start, :stop].each do |t|
  desc "#{t} task is a no-op with mod_rails"
  task t, :roles => :app do ; end
end

Without this capistrano was trying to get the www-data user to sudo to run script/spinner. Before I noticed the omission I was considering writing scripts to stop the server by disabling the virtual host, and reloading apache, and starting in in a similar manner, and giving www-data limited sudo privileges to run those scripts. It turns out that this is unnecessary using Passenger, so it was just a matter of overriding the default capistrano tasks to do nothing.

So now there was joy in Mudville. The cap deploy:cold worked. At this point I created a vhost configuration in /etc/apache2/sites-available, used a2ensite to enable it, and reloaded apache. Now to check it out.

One Last Wafer Thin Mint

Back on the MacBook, I edited /etc/hosts to now point to the servers lan address. I still wasn't ready to expose port 80 of the server to the internets.

I cranked up my browser and reloaded the url. Everything was working! But being the suspicious type, I wanted to make sure. Tailing the log on the server showed no acivity, hmmmm?

I pinged talklikeaduck.denhaven2.com on the MacBook, and it was pinging 127.0.0.1. I knew that I'd changed /etc/hosts. Ben told me over ichat to try dscacheutil -flushcache, which seemed to have no effect. So I rebooted the MacBook, and it was still resolving talklikeaduck.denhaven2.com to localhost.

At that point I tried:

$ dscacheutil -q host 127.0.0.1

Which produced:

name: talklikeaduck.denhaven2.com
ip_address: 127.0.0.1
name: localhost
ip_address: 127.0.0.1
name: talklikeaduck.denhaven2.com
ip_address: aaa.bbb.ccc.ddd

So there were two cache entries, and the local host one was winning.

I finally got a clue when I grepped /etc for references to talklikeaduck, and found one in /etc/hosts, but also one in /etc/apache2/sites-available/tlad which was the vhost configuration generated by Passenger pane. When I removed the blog project directory from the Passenger pane, and hit restart, then did the dscacheutil -flushcache, the name was now resolving to the server.

Now I was hitting the server, and I did a little more prodding to make sure things were working, including writing my resurrection announcement.

Now I was finally ready to unblock port 80 on the router.

Hopefully someone will find something useful in this post, at least I've captured the lessons I learned from the exercise.