<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>tag:airbladesoftware.com,2009:/</id>
  <title type="text">AirBlade Software</title>
  <updated>2012-02-07T00:00:00+00:00</updated>
  <generator uri="http://effectif.com/nesta">Nesta, modified by AirBlade</generator>
  <link href="http://airbladesoftware.com/feed/notes.xml" rel="self"/>
  <link href="http://airbladesoftware.com" rel="alternate"/>
  <subtitle type="text"></subtitle>
  <icon>/attachments/favicon.ico</icon>
  <author>
    <name>Andy Stewart</name>
    <uri>http://airbladesoftware.com</uri>
    <email>boss@airbladesoftware.com</email>
  </author>
  <entry>
    <id>tag:airbladesoftware.com,2012-02-07:/notes/give-me-a-better-hash-key</id>
    <title>Give Me A Better # Key</title>
    <updated>2012-02-07T00:00:00+00:00</updated>
    <link type="text/html" href="http://airbladesoftware.com/notes/give-me-a-better-hash-key" rel="alternate"/>
    <content type="html">&lt;p&gt;This is in reply to &lt;a href="http://woss.name/2011/12/30/give-me-back-my-hash-key/"&gt;Give me back my # key!&lt;/a&gt;  I was already doing my Vim thing but I didn&amp;rsquo;t realise I could map keys in &lt;a href="http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html"&gt;readline&lt;/a&gt; until I read that article.  Thanks Graeme!&lt;/p&gt;

&lt;p&gt;If you use a Mac in the UK and often type #, you may find the Option-3 key combo annoying.  I do.&lt;/p&gt;

&lt;p&gt;Fortunately there&amp;rsquo;s another key nearby which I never use: the &#167;/&#177; key underneath Escape.  We can map that to # and forget about the Option key.&lt;/p&gt;

&lt;h2&gt;Command line&lt;/h2&gt;

&lt;p&gt;To sort out your command line, add this to your &lt;code&gt;~/.inputrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;"&#167;": '#'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You&amp;rsquo;ll need to reload your &lt;a href="http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html"&gt;readline&lt;/a&gt; configuration, most easily by restarting Bash.&lt;/p&gt;

&lt;h2&gt;Vim&lt;/h2&gt;

&lt;p&gt;Vim is slightly trickier.  We want to map &#167; to # in insert mode and on the command line (for &lt;code&gt;:&lt;/code&gt; commands), but not in normal mode where &lt;a href="http://vimdoc.sourceforge.net/htmldoc/pattern.html##"&gt;#&lt;/a&gt; means the same as &lt;a href="http://vimdoc.sourceforge.net/htmldoc/pattern.html#star"&gt;*&lt;/a&gt; but backwards.  So far, so good.  But we also want to be able to replace a character with # using &lt;code&gt;r&#167;&lt;/code&gt;, and move forward to the next # with &lt;code&gt;f&#167;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Fortunately &lt;a href="http://groups.google.com/group/vim_mac/browse_thread/thread/19cdd0391cee42/"&gt;Ben Schmidt explained to me how to do this&lt;/a&gt;.  Add this to your &lt;code&gt;~/.vimrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;set iminsert=1
set imsearch=-1
noremap  &#167; #
noremap! &#167; #
lnoremap &#167; #
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;IRB&lt;/h2&gt;

&lt;p&gt;Unfortunately IRB doesn&amp;rsquo;t pay attention to your &lt;code&gt;~/.inputrc&lt;/code&gt;, as far as I can tell, even though it is supposed to integrate with readline.&lt;/p&gt;

&lt;p&gt;If anyone knows how to fix this, I&amp;rsquo;d love to hear about it!&lt;/p&gt;
</content>
    <published>2012-02-07T00:00:00+00:00</published>
    <category term="Development"/>
    <category term="OSX"/>
  </entry>
  <entry>
    <id>tag:airbladesoftware.com,2012-01-27:/notes/fixing-truncated-accented-text</id>
    <title>Fixing Truncated, Accented Text In MySQL</title>
    <updated>2012-01-27T00:00:00+00:00</updated>
    <link type="text/html" href="http://airbladesoftware.com/notes/fixing-truncated-accented-text" rel="alternate"/>
    <content type="html">&lt;p&gt;So &lt;a href="http://airbladesoftware.com/notes/fixing-mysql-illegal-mix-of-collations"&gt;when I loaded my data into MySQL&lt;/a&gt; the other day, MySQL silently truncated every piece of text at the first accented character.  This affected about 13,000 records.  The truncation was bad enough, though I suppose MySQL just couldn&amp;rsquo;t figure out what the byte stream meant at that point.  But to do it &lt;em&gt;silently&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Not cool.&lt;/p&gt;

&lt;p&gt;Why did MySQL truncate my text?  I have no idea.&lt;/p&gt;

&lt;h2&gt;The correct solution&lt;/h2&gt;

&lt;p&gt;Move to &lt;a href="http://www.postgresql.org"&gt;PostgreSQL&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;The solution in the meantime&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Find the affected records&lt;/li&gt;
&lt;li&gt;Extract their original, intact values from the old database&lt;/li&gt;
&lt;li&gt;Update the truncated records in the new database with the original values&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I couldn&amp;rsquo;t find the affected records in the new database because the truncated data was truly lost.  How do you query what&amp;rsquo;s not there?&lt;/p&gt;

&lt;p&gt;So I loaded my data dump into a fresh development database.  Strangely this worked despite having gone pear-shaped in production.&lt;/p&gt;

&lt;p&gt;I then looked for all texty fields in the database containing a French or German accent (based on my customers' languages) and generated a SQL script with their values.  The accent query below just wouldn&amp;rsquo;t work until I used the &lt;code&gt;binary&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the Rake task I wrote:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;task :fix_accents =&amp;gt; :environment do
  accents = %w[ &#223; &#228; &#235; &#246; &#252; &#233; &#224; &#232; &#226; &#244; ]
  ActiveRecord::Base.connection.tables.
    reject { |name| %w[delayed_jobs schema_migrations].include? name }.
    each do |table|
      klass = table.classify.constantize
      texty_columns = klass.columns_hash.
        select { |name,col| col.type == :string || col.type == :text }.
        map    { |name,col| name }.
        each do |name|
          accents.each do |accent|
            klass.select("id, `#{name}`").where("binary `#{name}` like '%#{accent}%'").each do |row|
              puts "UPDATE #{table} SET `#{name}` = #{row.send(name).inspect} WHERE id = #{row.id};"
            end
          end
        end
    end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I piped the output into a new file, tested a few key lines on the production database, then piped the whole thing into the production database.  Problem solved.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m still moving to PostreSQL though.&lt;/p&gt;
</content>
    <published>2012-01-27T00:00:00+00:00</published>
    <category term="MySQL"/>
    <category term="Rails"/>
  </entry>
  <entry>
    <id>tag:airbladesoftware.com,2012-01-24:/notes/fixing-mysql-illegal-mix-of-collations</id>
    <title>Fixing MySQL's Illegal Mix of Collations</title>
    <updated>2012-01-24T00:00:00+00:00</updated>
    <link type="text/html" href="http://airbladesoftware.com/notes/fixing-mysql-illegal-mix-of-collations" rel="alternate"/>
    <content type="html">&lt;p&gt;I recently started to encounter MySQL&amp;rsquo;s dreaded illegal-mix-of-collations error.  The occasional query would result in &lt;code&gt;Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;MySQL&amp;rsquo;s default character set is &lt;code&gt;latin1&lt;/code&gt; with an adventurous Swedish collation, which presumably seemed like a good idea at the time.  However Rails uses UTF-8 everywhere and from time to time the two collations collide.&lt;/p&gt;

&lt;p&gt;Fortunately this problem is not new and clever people have already solved it: see &lt;a href="http://www.bluebox.net/news/2009/07/mysql_encoding"&gt;Getting out of MySQL Character Set Hell&lt;/a&gt; and &lt;a href="http://alexking.org/blog/2008/03/06/mysql-latin1-utf8-conversion"&gt;Fixing a MySQL Character Encoding Mismatch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Those two articles advise more or less the same process.  Here I&amp;rsquo;m just jotting down some notes where I found something confusing or ambiguous in case I ever have to do this again.&lt;/p&gt;

&lt;h2&gt;Order of events&lt;/h2&gt;

&lt;p&gt;After exporting the data and hacking the dump file, I wasn&amp;rsquo;t sure whether to configure MySQL for UTF-8 and then import the data, or the other way round.&lt;/p&gt;

&lt;p&gt;I chose to import the data and then configure MySQL to avoid double-encoding the data.  &lt;strike&gt;It seems to have worked.&lt;/strike&gt;  It &lt;a href="http://airbladesoftware.com/notes/fixing-truncated-accented-text"&gt;silently truncated all my accented text&lt;/a&gt; but I was able to fix that.&lt;/p&gt;

&lt;h2&gt;Take stock&lt;/h2&gt;

&lt;p&gt;First figure out where you stand.  In MySQL do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysql&amp;gt; show variables like 'char%';
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The result you want is this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At this stage several of these values will be &lt;code&gt;latin1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Similarly for collation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysql&amp;gt; show variables like 'collation%';
+----------------------+-----------------+
| Variable_name        | Value           |
+----------------------+-----------------+
| collation_connection | utf8_general_ci |
| collation_database   | utf8_general_ci |
| collation_server     | utf8_general_ci |
+----------------------+-----------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;utf8_general_ci&lt;/code&gt; collation will do but ideally we want &lt;code&gt;utf8_unicode_ci&lt;/code&gt;.  The former basically ignores all accents: it treats &amp;lsquo;&#252;&amp;rsquo; the same as &amp;lsquo;u&amp;rsquo;.  The latter pays attention to accents; it&amp;rsquo;s a tiny bit slower but more accurate.&lt;/p&gt;

&lt;p&gt;To see what your tables are using:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysql&amp;gt; show table status \G
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;hellip;and look at the Collation field in each table.&lt;/p&gt;

&lt;h2&gt;Dumping your data as latin1&lt;/h2&gt;

&lt;p&gt;Here&amp;rsquo;s the command I used:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysqldump -uUSER -pPASSWORD --quick --single-transaction --create-options --skip-set-charset --default-character-set=latin1 DATABASE &amp;gt; dump.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;hellip;where USER, PASSWORD, and DATABASE should be replaced appropriately.&lt;/p&gt;

&lt;p&gt;My SQL dump was only 40MB so I was able to edit the tables' character sets in Vim (set &lt;code&gt;:syn off&lt;/code&gt; for speed).  In Vim:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:%s/DEFAULT CHARSET=latin1;/DEFAULT CHARSET=utf8;/
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Configuring MySQL to use UTF8&lt;/h2&gt;

&lt;p&gt;I added this configuration to &lt;code&gt;/etc/mysql/my.cnf&lt;/code&gt; (on Ubuntu 10.04):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[client]:
default-character-set=utf8

[mysqld]
default-character-set=utf8
default-collation=utf8_general_ci
character-set-server=utf8
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Although the &lt;a href="http://dev.mysql.com/doc/refman/5.1/en/server-options.html#option_mysqld_collation-server"&gt;documentation&lt;/a&gt; claims there is a &lt;code&gt;collation-server&lt;/code&gt; setting in the &lt;code&gt;[mysqld]&lt;/code&gt; section, using it prevented my mysql (v5.1.41) from starting up.  I ran up 30min of downtime trying to figure out why mysql wouldn&amp;rsquo;t start.&lt;/p&gt;

&lt;p&gt;After I had done all this and restarted mysql, I found all the &lt;code&gt;character_set_*&lt;/code&gt; variables were correct except &lt;code&gt;character_set_database&lt;/code&gt;.  To fix this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysql&amp;gt; alter database DATABASE default character set utf8;
mysql&amp;gt; alter database DATABASE default collate utf8_general_ci;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Verify with &lt;code&gt;show create database DATABASE&lt;/code&gt;.  (&lt;a href="http://dev.mysql.com/doc/refman/5.0/en/charset-database.html"&gt;Documentation&lt;/a&gt;.)&lt;/p&gt;

&lt;h2&gt;Verifying everything worked&lt;/h2&gt;

&lt;p&gt;In the MySQL console I ran these:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mysql&amp;gt; show variables like 'char%';
mysql&amp;gt; show variables like 'collation%';
mysql&amp;gt; show create database DATABASE;
mysql&amp;gt; show table status \G
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then in the Rails console:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; ActiveRecord::Base.connection.collation
"utf_general_ci"
&lt;/code&gt;&lt;/pre&gt;
</content>
    <published>2012-01-24T00:00:00+00:00</published>
    <category term="MySQL"/>
    <category term="Rails"/>
  </entry>
  <entry>
    <id>tag:airbladesoftware.com,2012-01-16:/notes/cleaning-up-code</id>
    <title>Cleaning Up Code</title>
    <updated>2012-01-16T00:00:00+00:00</updated>
    <link type="text/html" href="http://airbladesoftware.com/notes/cleaning-up-code" rel="alternate"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;I've found a good trick for fixing crufty code is to pretend I'm going to open-source it. It's like inviting guests over to your house.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;p&gt;&lt;cite&gt;&lt;a href="http://twitter.com/#!/Pinboard/status/157892337467523072"&gt;Maciej Ceg&#322;owski&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;I've used this trick for a while and it always works.&lt;/p&gt;



</content>
    <published>2012-01-16T00:00:00+00:00</published>
    <category term="Coding"/>
  </entry>
  <entry>
    <id>tag:airbladesoftware.com,2011-11-24:/notes/logging-subdomains-in-rails-3</id>
    <title>Logging Subdomains in Rails 3</title>
    <updated>2011-11-24T00:00:00+00:00</updated>
    <link type="text/html" href="http://airbladesoftware.com/notes/logging-subdomains-in-rails-3" rel="alternate"/>
    <content type="html">&lt;p&gt;Rails 3.2 will have &lt;a href="https://github.com/rails/rails/commit/afde6fdd5ef3e6b0693a7e330777e85ef4cffddb"&gt;tagged logging&lt;/a&gt; so you can stamp your logs with subdomains (among other things).  Until then you can use the Notifications API as follows.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;app/controllers/application_controller.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Put this before your other filters
before_filter :instrument_subdomain

private

def instrument_subdomain
  ActiveSupport::Notifications.instrument 'subdomain.action_controller', :subdomain =&amp;gt; request.subdomain
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In &lt;code&gt;config/initializers/notifications.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ActiveSupport::Notifications.subscribe 'subdomain.action_controller' do |name, start, finish, id, payload|
  Rails.logger.info "Subdomain: #{payload[:subdomain].presence || '[none]'}"
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now your logs will show each request&amp;rsquo;s subdomain.  For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Started GET "/dashboard" for 123.456.42.153 at 2011-11-24 10:43:52 +0000
  Processing by DashboardsController#show as HTML
Subdomain: bigclient
Rendered dashboards/show.html.haml within layouts/account (15.4ms)
Completed 200 OK in 97ms (Views: 16.1ms | ActiveRecord: 32.3ms | Sphinx: 0.0ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This lets you see who&amp;rsquo;s doing what when you browse the logs.&lt;/p&gt;

&lt;p&gt;In terms of bang for the buck, or utility per line of code, this was one of my better commits.&lt;/p&gt;
</content>
    <published>2011-11-24T00:00:00+00:00</published>
    <category term="Rails"/>
  </entry>
  <entry>
    <id>tag:airbladesoftware.com,2011-11-21:/notes/managing-monit-with-upstart</id>
    <title>Managing Monit with Upstart</title>
    <updated>2011-11-21T00:00:00+00:00</updated>
    <link type="text/html" href="http://airbladesoftware.com/notes/managing-monit-with-upstart" rel="alternate"/>
    <content type="html">&lt;p&gt;I just moved my production server from a Centos 4.6 VPS to Ubuntu 10.04.  I had been quite happy with the Centos &amp;mdash; but I&amp;rsquo;ve discovered Ubuntu is far nicer.  The packages are more up to date and it feels like considerably more thought has gone into it.&lt;/p&gt;

&lt;p&gt;Ubuntu uses &lt;a href="http://upstart.ubuntu.com"&gt;Upstart&lt;/a&gt; to manage its services.  While Upstart is excellent at starting services and keeping them up, it has limited ability to restart services when they grow too big for their boots.  Furthermore, not every service has been moved over to Upstart&amp;rsquo;s management; some &amp;mdash; in particular Apache &amp;mdash; are still managed the legacy &lt;code&gt;init.d&lt;/code&gt; way.&lt;/p&gt;

&lt;p&gt;So we need another process manager.&lt;/p&gt;

&lt;h2&gt;Monit&lt;/h2&gt;

&lt;p&gt;I like &lt;a href="http://mmonit.com/monit"&gt;monit&lt;/a&gt;.  It solves the Apache problem and the proactive-restart problem, but now we need to manage Monit itself.  Upstart is the future so we&amp;rsquo;ll use that.&lt;/p&gt;

&lt;p&gt;First we disengage &lt;code&gt;init.d&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo /etc/init.d/monit stop
$ sudo update-rc.d -f monit remove
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we configure an Upstart job in &lt;code&gt;/etc/init/monit.conf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;start on runlevel [2345]
stop on runlevel [06]
respawn
exec /usr/locall/bin/monit -Ic /etc/monit/monitc
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;N.B. I&amp;rsquo;m not sure whether the stop runlevels should include &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next we edit &lt;code&gt;/etc/default/monit&lt;/code&gt; and change &lt;code&gt;startup=0&lt;/code&gt; to &lt;code&gt;startup=1&lt;/code&gt;.  (I&amp;rsquo;m not sure whether this is necessary but it doesn&amp;rsquo;t hurt.)&lt;/p&gt;

&lt;p&gt;Finally we activate Upstart:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo start monit
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We can use Monit to manage services which Upstart doesn&amp;rsquo;t yet manage, and Upstart to manage Monit.  And Monit can cut tall poppies down to size whenever needed.&lt;/p&gt;

&lt;p&gt;Hopefully in due course Upstart will encompass all of the above.  In the meantime this works for me.&lt;/p&gt;
</content>
    <published>2011-11-21T00:00:00+00:00</published>
    <category term="Deployment"/>
  </entry>
  <entry>
    <id>tag:airbladesoftware.com,2011-11-09:/notes/excel-export</id>
    <title>Export to Excel in Rails 3</title>
    <updated>2011-11-09T12:00:00+00:00</updated>
    <link type="text/html" href="http://airbladesoftware.com/notes/excel-export" rel="alternate"/>
    <content type="html">&lt;p&gt;Recently I added the ability to export data to Excel from a Rails 3 webapp.  There were pleasingly few lines of code.&lt;/p&gt;

&lt;h2&gt;The Code&lt;/h2&gt;

&lt;p&gt;In config/initializers/mime_types.rb:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Mime::Type.register 'application/vnd.ms-excel', :xls
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In config/initializers/xls_renderer.rb:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ActionController::Renderers.add :xls do |xls, options|
  send_data(xls.respond_to?(:to_xls) ? xls.to_xls(options) : xls, :type =&amp;gt; :xls)
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In Gemfile:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gem 'to_xls', '~&amp;gt; 1.0.0'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the view:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;link_to 'Export to Excel', url_for(:format =&amp;gt; 'xls')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the controller:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def index
  @widgets = Widget.all
  respond_to do |format|
    format.html
    format.xls do
      render :xls =&amp;gt; @widgets,
                     :columns =&amp;gt; [ :name, :ref ],
                     :headers =&amp;gt; %w[ Name Reference ]
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;The Tests&lt;/h2&gt;

&lt;p&gt;In test/unit/xls_renderer_test.rb:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require 'test_helper'
class XlsRendererTest &amp;lt; ActiveSupport::TestCase
  test 'xls mime type' do
    assert_equal :xls, Mime::XLS.to_sym
    assert_equal 'application/vnd.ms-excel', Mime::XLS.to_s
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In features/step_definitions/excel_steps.rb:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Then /^I should download an Excel document$/ do
  assert_equal 'binary',                   page.response_headers['Content-Transfer-Encoding']
  assert_equal 'application/vnd.ms-excel', page.response_headers['Content-Type']
  assert_equal 'attachment',               page.response_headers['Content-Disposition']
  assert page.source.length &amp;gt; 0  # not ideal but better than nothing
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In features/whatever.feature:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Scenario: export to Excel
  When I go to the whatever page
  And I follow "Export to Excel"
  Then I should download an Excel document
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;References&lt;/h2&gt;

&lt;p&gt;The best source of information I found was Jos&#233; Valim&amp;rsquo;s &lt;a href="http://pragprog.com/book/jvrails/crafting-rails-applications"&gt;Crafting Rails Applications&lt;/a&gt;.  I like this book because it&amp;rsquo;s non-trivial and it explains everything test first.&lt;/p&gt;
</content>
    <published>2011-11-09T12:00:00+00:00</published>
    <category term="Rails"/>
  </entry>
  <entry>
    <id>tag:airbladesoftware.com,2011-11-09:/notes/social-graph</id>
    <title>The Social Graph</title>
    <updated>2011-11-09T00:00:00+00:00</updated>
    <link type="text/html" href="http://airbladesoftware.com/notes/social-graph" rel="alternate"/>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Imagine the U.S. Census as conducted by direct marketers - that's the social graph.&lt;/p&gt;

&lt;p&gt;Social networks exist to sell you crap. The icky feeling you get when your friend starts to talk to you about Amway, or when you spot someone passing out business cards at a birthday party, is the entire driving force behind a site like Facebook.&lt;/p&gt;

&lt;p&gt;Because their collection methods are kind of primitive, these sites have to coax you into doing as much of your social interaction as possible while logged in, so they can see it. It's as if an ad agency built a nationwide chain of pubs and night clubs in the hopes that people would spend all their time there, rigging the place with microphones and cameras to keep abreast of the latest trends (and staffing it, of course, with that Mormon bartender).&lt;/p&gt;

&lt;p&gt;We're used to talking about how disturbing this in the context of privacy, but it's worth pointing out how weirdly unsocial it is, too. How are you supposed to feel at home when you know a place is full of one-way mirrors?&lt;/p&gt;

&lt;p&gt;We have a name for the kind of person who collects a detailed, permanent dossier on everyone they interact with, with the intent of using it to manipulate others for personal advantage - we call that person a sociopath. And both Google and Facebook have gone deep into stalker territory with their attempts to track our every action. Even if you have faith in their good intentions, you feel misgivings about stepping into the elaborate shrine they've built to document your entire online life.&lt;/p&gt;

&lt;p&gt;Open data advocates tell us the answer is to reclaim this obsessive dossier for ourselves, so we can decide where to store it. But this misses the point of how stifling it is to have such a permanent record in the first place. Who does that kind of thing and calls it social?&lt;/p&gt;
&lt;/blockquote&gt;


&lt;p&gt;&lt;cite&gt;Maciej Ceg&#322;owski, &lt;a href="http://blog.pinboard.in/2011/11/the_social_graph_is_neither/"&gt;The Social Graph is Neither&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;h2&gt;Social Networks I&amp;rsquo;m Not In&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;m not on Facebook, Google+, or Flickr.  I see they&amp;rsquo;re a convenient way of sharing photos and snippets of news, but I know they would decrease the quality of my friendships.  I already struggle to find time regularly to meet, phone, or write to friends; pfaffing on a social network would use up that precious time and make me feel I&amp;rsquo;d done enough when, in reality, it&amp;rsquo;s not enough.&lt;/p&gt;

&lt;p&gt;Also I don&amp;rsquo;t see why these networks should have all the intellectual property rights to my stuff.&lt;/p&gt;

&lt;h2&gt;Social Networks I Am In&lt;/h2&gt;

&lt;p&gt;I am on &lt;a href="https://github.com/airblade"&gt;GitHub&lt;/a&gt;, &lt;a href="http://twitter.com/#!/airblade"&gt;Twitter&lt;/a&gt;, and &lt;a href="http://uk.linkedin.com/pub/andrew-stewart/2/935/271"&gt;LinkedIn&lt;/a&gt;.  The difference is these are all for work: to try to get more business.  Even this blog exists only to try to get people to give me money; it&amp;rsquo;s not a diary to show the world I am a unique and beautiful snowflake.  (Obviously I am but I don&amp;rsquo;t feel the need to tell anyone that.)&lt;/p&gt;
</content>
    <published>2011-11-09T00:00:00+00:00</published>
    <category term="Social"/>
  </entry>
  <entry>
    <id>tag:airbladesoftware.com,2011-11-08:/notes/dns-downtime</id>
    <title>DNS Downtime</title>
    <updated>2011-11-08T00:00:00+00:00</updated>
    <link type="text/html" href="http://airbladesoftware.com/notes/dns-downtime" rel="alternate"/>
    <content type="html">&lt;p&gt;I use Dyn&amp;rsquo;s &lt;a href="http://dyn.com/dns/dyn-standard-dns/"&gt;Standard DNS&lt;/a&gt; for my company&amp;rsquo;s and my customers' DNS.  The service is excellent and the web interface first rate.&lt;/p&gt;

&lt;p&gt;Until yesterday it was the only internet service I knew of with a 100% uptime &amp;mdash; a remarkable feat.  It had to end sometime&amp;hellip;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So today, for the first time since 2001, we experienced a full 22 minute outage of our Dyn Standard DNS nameservers, which means that we reset our Dyn Standard DNS uptime counters back to zero.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;p&gt;&lt;cite&gt;&lt;a href="http://dyn.com/post-mortem-attack-to-dyn-standard-dns-nameservers/"&gt;Post Mortem: Attack To Dyn Standard DNS Nameservers&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;Dyn&amp;rsquo;s pricier &lt;a href="http://dyn.com/dns/dynect-managed-dns/"&gt;Managed DNS&lt;/a&gt; platform kept on trucking without incident but unfortunately I&amp;rsquo;m not in a position to upgrade just yet!&lt;/p&gt;

&lt;p&gt;When you think about all the things that have to operate when you ask your browser to pull up a URL, it&amp;rsquo;s amazing that it works at all.&lt;/p&gt;
</content>
    <published>2011-11-08T00:00:00+00:00</published>
    <category term="DNS"/>
  </entry>
  <entry>
    <id>tag:airbladesoftware.com,2011-10-20:/notes/rbenv-in-production</id>
    <title>Using rbenv in Production</title>
    <updated>2011-10-20T00:00:00+00:00</updated>
    <link type="text/html" href="http://airbladesoftware.com/notes/rbenv-in-production" rel="alternate"/>
    <content type="html">&lt;p&gt;I just switched to using &lt;a href="https://github.com/sstephenson/rbenv"&gt;rbenv&lt;/a&gt; in production so I could easily upgrade to Ruby 1.9.2-p290.  37signals uses rbenv in production like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Each app is isolated through disciplined use of RubyGems/Bundler-style binstubs. We start with the stubs Bundler generates (&lt;code&gt;bundle install --binstubs&lt;/code&gt;) and change the shebang from &lt;code&gt;#!/usr/bin/env ruby&lt;/code&gt; to &lt;code&gt;usr/bin/env ruby-local-exec&lt;/code&gt;. Update your Capistrano recipes, Chef cookbooks, Bluepill config, etc to use these binstubs throughout.&lt;/p&gt;

&lt;p&gt;This draws a solid line between your app and your ops, meeting at just a handful of binstubs.&lt;/p&gt;

&lt;p&gt;Now executing &lt;code&gt;/u/apps/basecamp/current/bin/unicorn&lt;/code&gt; uses the Ruby in &lt;code&gt;/u/apps/basecamp/current/.rbenv-version&lt;/code&gt; and the Unicorn bundled in &lt;code&gt;/u/apps/basecamp/current/Gemfile.lock&lt;/code&gt;. Your app is self-contained. Your ops tools no longer know or care whether you use Bundler or whether you're on 1.8.7 or 1.9.3. Achievement unlocked.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;p&gt;&lt;cite&gt;&lt;a href="https://github.com/sstephenson/rbenv/issues/101#issuecomment-2258506"&gt;Jeremy Kemper&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;h2&gt;Shebangs and binstubs&lt;/h2&gt;

&lt;p&gt;As far as I can tell, binstubs have two advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nothing else need know you use Bundler.&lt;/li&gt;
&lt;li&gt;You don&amp;rsquo;t need to change into the app directory before running a command.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;However I couldn&amp;rsquo;t get the Rails runner to work via a binstub, and I don&amp;rsquo;t mind if my &amp;ldquo;ops tools&amp;rdquo; know about Bundler.  So I decided to forgo the binstubs and stick with &lt;code&gt;bundle exec&lt;/code&gt;.  Since I&amp;rsquo;m using the same Ruby everywhere on the server, via &lt;code&gt;rbenv global 1.9.2-p290&lt;/code&gt;, it&amp;rsquo;s fine.&lt;/p&gt;

&lt;p&gt;But I did need to update my app&amp;rsquo;s scripts' shebangs to &lt;code&gt;&lt;a href="https://github.com/sstephenson/rbenv/blob/master/bin/ruby-local-exec"&gt;ruby-local-exec&lt;/a&gt;&lt;/code&gt;; for example &lt;code&gt;script/rails&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/usr/bin/env ruby-local-exec
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.

APP_PATH = File.expand_path('../../config/application',  __FILE__)
require File.expand_path('../../config/boot',  __FILE__)
require 'rails/commands'
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Passenger&lt;/h2&gt;

&lt;p&gt;Don&amp;rsquo;t forget to re-install Passenger in your rbenv-managed Ruby, and &lt;code&gt;rbenv rehash&lt;/code&gt; afterwards.&lt;/p&gt;

&lt;p&gt;And on Apache, you&amp;rsquo;ll also need to update the Passenger configuration to use the new Ruby.&lt;/p&gt;

&lt;h2&gt;Non-app gems&lt;/h2&gt;

&lt;p&gt;You&amp;rsquo;ll also need to install (and &lt;code&gt;rbenv rehash&lt;/code&gt;) non-Gemfile gems, such as those your crontab commands use.  For example I use a gem via cron to backup the database to S3.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;With rbenv managing Ruby, and Bundler managing my app&amp;rsquo;s gems, everything is nicely isolated.  As Jeremey Kemper went on to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Now, say Ruby 1.9.3-rc1 just came out and you want to upgrade your app. Push the new package to your servers (using Chef or whatever), change &lt;code&gt;.rbenv-version&lt;/code&gt; from 1.9.3-preview1 to 1.9.3-rc1, and &lt;code&gt;cap deploy&lt;/code&gt;. That's it.&lt;/p&gt;

&lt;p&gt;Didn't work out? &lt;code&gt;cap deploy:rollback&lt;/code&gt; and you're back at 1.9.3-preview1. Ahh.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;p&gt;Which is lucky, because my Rails 3.0.10 app takes a glacial 3m47s to start up on Ruby 1.9.2-p290.  As my friend Kamyar says, that&amp;rsquo;s not a computer number: ~4 minutes on modern CPUs corresponds to gazillions of instructions and we are not modelling the climate here.&lt;/p&gt;

&lt;p&gt;So I&amp;rsquo;m going to take advantage of my easily-upgradable environment and &lt;a href="https://github.com/sstephenson/ruby-build/issues/65"&gt;upgrade to 1.9.3-rc1&lt;/a&gt; as soon as possible.&lt;/p&gt;
</content>
    <published>2011-10-20T00:00:00+00:00</published>
    <category term="Ruby"/>
    <category term="Deployment"/>
  </entry>
</feed>

<!-- page cached: 2012-07-02 08:02:18 -->


