alex's blog

Clean up a subversion working copy

You could just delete your working copy and check out a fresh one. In my case, that takes hours. So I wanted to find a way to remove all local modifications.

svn st | awk '{ if ( $1 == "?" ) print $2 }' | xargs rm -Rf
svn st | awk '{ if ( $1 == "M" ) print $2 }' | xargs svn revert

Remove all files whos' svn status is '?', meaning not part of version control. Then revert changes in any file which has an "M" (modified) status.

svt st

You should now have no local changes or unknown files.

WARNING
xargs may not do the right this if your file names have spaces or other special characters in them. Check man xargs for more details before running these commands.

Demo of automatic merge tracking in Subversion 1.5

Create a Demo Project

I'll create a basic project to demonstrate how the merge-tracking features in Subversion 1.5 work. This isn't exactly new, but it's new to me since our company just upgraded our svn server.

$ svnadmin create frobulator-repo
$ mkdir skeleton
$ mkdir skeleton/trunk
$ touch skeleton/trunk/frob.rb
$ mkdir skeleton/branches
$ mkdir skeleton/branches/release-1.0.0
$ cp skeleton/trunk/frob.rb skeleton/branches/release-1.0.0/
$ svn import skeleton file:///Users/alex/tmp/frobulator-repo -m 'initial import'
Adding         skeleton/trunk
Adding         skeleton/trunk/frob.rb
Adding         skeleton/branches
Adding         skeleton/branches/release-1.0.0
Adding         skeleton/branches/release-1.0.0/frob.rb

Committed revision 1.
$ svn co file:///Users/alex/tmp/frobulator-repo frobulator-wc
A    frobulator-wc/trunk
A    frobulator-wc/trunk/frob.rb
A    frobulator-wc/branches
A    frobulator-wc/branches/release-1.0.0
A    frobulator-wc/branches/release-1.0.0/frob.rb
Checked out revision 1.

Make a Change

So far, I've created a new repository with a trunk and 1 branch. The trunk and branch have identical content right now, a single empty frob.rb file.

I'll fix a 'bug' in the trunk now.

$ cd frobulator-wc/trunk
frobulator-wc/trunk$ echo 'puts "bug fixed!"' > frob.rb
frobulator-wc/trunk$ svn commit -m 'fixed bug in frob.rb'
Sending        trunk/frob.rb
Transmitting file data .
Committed revision 2.

Merge Fix

Now I want to merge my bug fix into my release branch.

frobulator-wc/trunk$ cd ../branches/release-1.0.0/
frobulator-wc/branches/release-1.0.0$ svn merge -c 2 file:///Users/alex/tmp/frobulator-repo/trunk .
--- Merging r2 into '.':
U    frob.rb
frobulator-wc/branches/release-1.0.0$ svn commit -m 'merge bug fix from trunk'
Sending        release-1.0.0
Sending        release-1.0.0/frob.rb
Transmitting file data .
Committed revision 3.

View Basic Log

Up to this point, there's nothing different from how I would have done things in subversion 1.4, except that my commit in the branch didn't mention where the merge came from. Formerly, I would have added a commit log like "merged trunk r2 into release-1.0.0". Otherwise we wouldn't have known what got merged and what didn't.

Notice the log only shows changes which were made in this branch. This behavior is the same as in previous version of Subversion.

frobulator-wc/branches/release-1.0.0$ svn log -v
------------------------------------------------------------------------
r3 | alex | 2010-07-27 09:08:43 -0500 (Tue, 27 Jul 2010) | 1 line
Changed paths:
   M /branches/release-1.0.0
   M /branches/release-1.0.0/frob.rb

merge bug fix from trunk
------------------------------------------------------------------------
r1 | alex | 2010-07-27 09:04:51 -0500 (Tue, 27 Jul 2010) | 1 line
Changed paths:
   A /branches
   A /branches/release-1.0.0
   A /branches/release-1.0.0/frob.rb
   A /trunk
   A /trunk/frob.rb

initial import
------------------------------------------------------------------------

View Merge Information in Log

This is where the new merge-tracking features in Subversion 1.5 show themselves. Adding the -g flag displays revision 2 as being part of release-1.0.0, and adds a note describing when this change was merged into the branch. Pretty nice.

frobulator-wc/branches/release-1.0.0$ svn log -vg
------------------------------------------------------------------------
r3 | alex | 2010-07-27 09:08:43 -0500 (Tue, 27 Jul 2010) | 1 line
Changed paths:
   M /branches/release-1.0.0
   M /branches/release-1.0.0/frob.rb

merge bug fix from trunk
------------------------------------------------------------------------
r2 | alex | 2010-07-27 09:07:15 -0500 (Tue, 27 Jul 2010) | 1 line
Changed paths:
   M /trunk/frob.rb
Merged via: r3

fixed bug in frob.rb
------------------------------------------------------------------------
r1 | alex | 2010-07-27 09:04:51 -0500 (Tue, 27 Jul 2010) | 1 line
Changed paths:
   A /branches
   A /branches/release-1.0.0
   A /branches/release-1.0.0/frob.rb
   A /trunk
   A /trunk/frob.rb

initial import
------------------------------------------------------------------------

ActiveRecord annoyance

class AnExampleWhichAnnoysMe < ActiveRecord::Migration
  def self.up
    create_table :test do |t|
      t.column :column_a, :integer
    end
    add_column :test, :column_b, :integer
    add_index :test, :column_b, :name=>'idx_on_test_col_b'
  end

  def self.down
    remove_index :test, :name=>'idx_on_test_col_b'
    remove_column :test, :column_b
    drop_table :test
  end
end

  • Columns: add & remove.
  • Indexes: add & remove.
  • Tables: create & drop.

I wish these were more consistent. The names seem to be based on common SQL commands, but for that to be a useful rule-of-thumb, columns and indexes should be manipulated through some 'alter' method, since ALTER is usually the command you use to change these kinds of objects in SQL. In the context of ActiveRecord, I can see that add & drop really make more sense, but I wish that logic would have been applied to tables as well.

As it is, I often make the mistake of using create_table and drop_index.

Semitic Markup

Everybody talks about the importance of semantic markup on the web.

I think Semitic markup isn't getting nearly enough attention.

I love xmlformat

There have been many times that I've captured some machine-generated XML document for debugging purposes. Usually these documents omit all line breaks, indentation, and other niceties which make the text more readable. Of course no real XML parser cares about such things, but the very-incomplete XML parser in my head really appreciates them. I've spent plenty of time manually re-formatting various documents to get them into some state where I could understand the structure and makes some sense out of it.

But, wow, that is tedious work. Click, enter, space, space, click, enter, space, space, etc, etc, etc... I went looking for a better solution, and found xmlformat. You can also use tidy, which is included on OSX by default. I prefer xmlformat because of the ease of configuration.

alex@rutabaga:~$ xmlformat --show-config
*DEFAULT
  format = block
  entry-break = 1
  element-break = 1
  exit-break = 1
  subindent = 2
  normalize = no
  wrap-length = 0

*DOCUMENT
  format = block
  entry-break = 0
  element-break = 1
  exit-break = 1
  subindent = 0
  normalize = no
  wrap-length = 0

This is pretty much the default configuration. I keep my configuration in ~/.xmlformat.conf, and set export XMLFORMAT_CONF=~/.xmlformat.conf in my ~/.profile script.

Why is this good?

With a single command:

alex@rutabaga:~$ xmlformat wfs_getfeature.xml

This mess:

<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.1.0" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><wfs:Query typeName="kodos:" srsName="EPSG:4326" xmlns:kodos="http://www.regionsproject.org/kodos"><ogc:Filter xmlns:ogc="http://www.opengis.net/ogc"><ogc:And><ogc:PropertyIsLessThan><ogc:PropertyName>map_id</ogc:PropertyName><ogc:Literal>0</ogc:Literal></ogc:PropertyIsLessThan><ogc:BBOX><ogc:PropertyName>area</ogc:PropertyName><gml:Envelope xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326"><gml:lowerCorner>-227.08007812014 0.922841119201</gml:lowerCorner><gml:upperCorner>17.08007812012 68.341004876129</gml:upperCorner></gml:Envelope></ogc:BBOX></ogc:And></ogc:Filter></wfs:Query></wfs:GetFeature>

is transformed into this:

<wfs:GetFeature xmlns:wfs="http://www.opengis.net/wfs" service="WFS" version="1.1.0" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <wfs:Query typeName="kodos:" srsName="EPSG:4326" xmlns:kodos="http://www.regionsproject.org/kodos">
    <ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
      <ogc:And>
        <ogc:PropertyIsLessThan>
          <ogc:PropertyName>map_id</ogc:PropertyName>
          <ogc:Literal>0</ogc:Literal>
        </ogc:PropertyIsLessThan>
        <ogc:BBOX>
          <ogc:PropertyName>area</ogc:PropertyName>
          <gml:Envelope xmlns:gml="http://www.opengis.net/gml" srsName="EPSG:4326">
            <gml:lowerCorner>-227.08007812014 0.922841119201</gml:lowerCorner>
            <gml:upperCorner>17.08007812012 68.341004876129</gml:upperCorner>
          </gml:Envelope>
        </ogc:BBOX>
      </ogc:And>
    </ogc:Filter>
  </wfs:Query>
</wfs:GetFeature>

It's now easy to see what elements are nested inside which other elements. This makes all kinds of debugging and troubleshooting tasks immensely easier.

Uploading GeoTIFFs to GeoServer via REST

A while ago I wanted to be able to upload a GeoTIFF to GeoServer via their REST interface. The default way to do this is to send the GeoTIFF image in an HTTP PUT. In my case, the image was already on the same filesystem as GeoServer's data directory, so sending it again in another HTTP transaction seemed like kind of a waste. I was hoping to find a way to just tell GeoServer to use the GeoTIFF in its current location, without the need to make a copy of the file.

I poked around in the source code for GeoServer's REST extension and discovered that this behavior was indeed supported. It just wasn't documented. A while ago I submitted some documentation additions which should make this clearer. This is a common use case, judging by the number of people who ask about this kind of thing on the GeoServer user's mailing list. So, until my patch gets accepted and makes its way into the official GeoServer REST API docs, I thought I'd point it out for anyone searching for a way to get GeoServer to use GeoTIFFs which are outside the data directory.

http://jira.codehaus.org/browse/GEOS-3966

Enjoy.

If you have polygon data, don't try to render it as points!

11 May 09:27:51 ERROR [geotools.rendering] - side location conflict [ (462.7099002767874, 220.80214145084886, NaN) ]
com.vividsolutions.jts.geom.TopologyException: side location conflict [ (462.7099002767874, 220.80214145084886, NaN) ]

This error occurs sometimes when you use a point-style SLD for a polygon layer. When adding new layers via the GeoServer web interface, the 'point' style is the default, so if you're just wanting a quick preview of your data you might forget to select an appropriate style and then encounter this error.

I'm not sure why some polygon layers can actually be rendered as points, while others raise this exception. In any case, I didn't find much information when searching for this specific error message, so I thought others might find this helpful.

Software Name of the Year

OSX Snow Leopard Not Finding Local DNS Names

We upgraded Sara's iMac to OSX 10.6. Mostly this is fine, but a few things are broken. Local DNS was one main problem. We have all our local machines in the '.dean' domain, and while I was able to correctly look up these names using dig, I wasn't able to actually use them in Firefox, ssh, or any other program.

The problem seems to be that 10.6 does not respect a DNS response with a TTL (time to live) of 0, which is the default value used by DNSMasq, the DNS/DHCP server which we use as part of DD-WRT.

The problem is described in this thread, in a posting by 'hphoto' dated '09-22-2009, 04:25 PM'.
http://www.mac-forums.com/forums/os-x-operating-system/164649-snow-leopa...

The advice seems to be right-on. Raising the TTL to some non-0 value for local DNS seems to solve the problem. I chose 5 seconds for mine.

alex@schlitz:~$ dig grawp.dean

; <<>> DiG 9.4.3-P3 <<>> grawp.dean
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26685
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;grawp.dean.                    IN      A

;; ANSWER SECTION:
grawp.dean.             0       IN      A       192.168.0.1

;; Query time: 13 msec
;; SERVER: 192.168.0.100#53(192.168.1.2)
;; WHEN: Fri Apr  2 21:46:05 2010
;; MSG SIZE  rcvd: 44

Notice the '0' in the ANSWER SECTION. That's the TTL.

Now go to the DD-WRT admin page for DNS options:

dd-wrt_admin

And add a 'local-ttl' value.

dnsmasq_options

Then save your options.

These pages were useful for reference.
http://www.dd-wrt.com/wiki/index.php/DNSMasq_as_DHCP_server
http://www.thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html

Notice that the options in the man page seem to be usable by just dropping the '--' from the long version of the option. So '--local-ttl=5' in the command-line version becomes just 'local-ttl=5' in the DD-WRT web interface.

Now, you can re-try that dig query to see the changed value.

alex@schlitz:~$ dig grawp.dean

; <<>> DiG 9.4.3-P3 <<>> grawp.dean
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26685
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;grawp.dean.                    IN      A

;; ANSWER SECTION:
grawp.dean.             5       IN      A       192.168.0.1

;; Query time: 13 msec
;; SERVER: 192.168.0.100#53(192.168.1.2)
;; WHEN: Fri Apr  2 21:46:05 2010
;; MSG SIZE  rcvd: 44

Hope that helps!


DIscover the character encoding used by a Postgres database

Postgres has a single character encoding per database. It can also silently translate from different client encodings to the one configured for the server. So Postgres is pretty flexible and can handle most text you throw at it.

But, if you ever need or want to know, it's simple to discover what encoding is being used by the server.

$ psql
Welcome to psql 8.3.1, the PostgreSQL interactive terminal.

Type:  \copyright for distribution terms
       \h for help with SQL commands
       \? for help with psql commands
       \g or terminate with semicolon to execute query
       \q to quit

testdb=# show server_encoding;
 server_encoding
-----------------
 UTF8
(1 row)

Seeing what encoding is in use by your client is just as easy.

testdb=# show client_encoding;
 client_encoding
-----------------
 UTF8
(1 row)

http://www.postgresql.org/docs/8.3/static/multibyte.html

Adding more disk space to an LVM-based partition in Red Hat 5

In this example, I have a Red Hat 5 VM running in VMWare Fusion on a MacBook Pro. The '/' partition is on a single LVM logical volume. I want to increase its size from 20GB to 25GB. If you're not using LVM, try these instructions instead : http://www.howtoforge.com/linux_resizing_ext3_partitions_p2

Here's the problem:

[root@rhel5-oracle ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
                       19G   18G  6.2M 100% /
/dev/sda1              99M   18M   77M  19% /boot
tmpfs                 506M     0  506M   0% /dev/shm

First step is to shut down the VM and give it more disk space via the VMWare 'Settings' panel. In this example, I just added space to the existing single virtual disk, but you could just as well create a separate virtual disk. The instructions below work just as well if you've got a non-virtual OS which you want to add more real physical storage to.

Then boot the VM again, and do the following in the guest OS.

fdisk /dev/sda

Create a new partition for the newly available space.

## Check what you're starting with.
Command (m for help): p

Disk /dev/sda: 26.8 GB, 26843545600 bytes
255 heads, 63 sectors/track, 3263 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          13      104391   83  Linux
/dev/sda2              14        2610    20860402+  8e  Linux LVM

## Create the new partition
Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 3
First cylinder (2611-3263, default 2611):
Using default value 2611
Last cylinder or +size or +sizeM or +sizeK (2611-3263, default 3263):
Using default value 3263

## Make it LVM
Command (m for help): t
Partition number (1-4): 3
Hex code (type L to list codes): 8e
Changed system type of partition 3 to 8e (Linux LVM)

## Double-check
Command (m for help): p

Disk /dev/sda: 26.8 GB, 26843545600 bytes
255 heads, 63 sectors/track, 3263 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          13      104391   83  Linux
/dev/sda2              14        2610    20860402+  8e  Linux LVM
/dev/sda3            2611        3263     5245222+  8e  Linux LVM

## Commit your changes
Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table.
The new table will be used at the next reboot.
Syncing disks.

Now reboot the VM and proceed. Online resizing of ext3 is supported in 2.6 kernels, so you don't even need to use Knoppix or some other CD-based distro.

[root@rhel5-oracle ~]# pvcreate /dev/sda3
  Physical volume "/dev/sda3" successfully created
[root@rhel5-oracle ~]# vgextend VolGroup00 /dev/sda3
  Volume group "VolGroup00" successfully extended
[root@rhel5-oracle ~]# lvextend -L+5G /dev/VolGroup00/LogVol00
  Extending logical volume LogVol00 to 23.88 GB
  Logical volume LogVol00 successfully resized
[root@rhel5-oracle ~]# resize2fs /dev/mapper/VolGroup00-LogVol00

And here's the final outcome...

[root@rhel5-oracle ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
                       24G   18G  4.6G  80% /
/dev/sda1              99M   18M   77M  19% /boot
tmpfs                 506M     0  506M   0% /dev/shm

Determine which process is listening on a TCP port in Linux

Note to self...

[root@rhel5-oracle ~]$ lsof -i tcp:1521 -nP
COMMAND  PID   USER   FD   TYPE DEVICE SIZE NODE NAME
tnslsnr 5640 oracle   10u  IPv4  11104       TCP *:1521 (LISTEN)
tnslsnr 5640 oracle   12u  IPv4  11424       TCP 127.0.0.1:1521->127.0.0.1:10948 (ESTABLISHED)
oracle  5742 oracle   16u  IPv4  11423       TCP 127.0.0.1:10948->127.0.0.1:1521 (ESTABLISHED)

Which environment is it, really?

UPDATE : April 21, 2010

http://www.jonmaddox.com/2008/03/13/show-your-git-branch-name-in-your-pr...
I like how this guy does something similar, but uses variable names for the color codes to make the resulting $PS1 string a bit more readable.


Rails uses the environment variable $RAILS_ENV to control which set of configuration files should be loaded. This includes, among many other things, what database to connect to. I tend to have lots of terminal windows open, doing several things at once. There are lots of circumstances where it's useful to switch to a different Rails environment for some tasks. The danger here, though, is that plenty of things you might do in a personal local development environment aren't at all safe to do in a production environment. (Dropping and re-loading test data into the production database is a particular no-no.)

I used to frequently echo $RAILS_ENV to check what a particular terminal window was set to. The trouble is it's easy to forget to do this. Having multiple terminals in multiple environments becomes a time bomb waiting to go off.

The solution I cooked up is to add some information about my $RAILS_ENV right in the terminal prompt. The concept is pretty simple, but getting the particular bash incantation correct took some doing. Adding this to your .profile in OSX will give you a colored prompt. Green for 'development', and red for any other environment. Should be pretty easy to fine-tune for your specific needs.

export RAILS_ENV=development
export PS1='`if [ "$RAILS_ENV" == "development" ]; then echo -n "\[\033[01;32m\]"; else echo -n "\[\033[01;31m\]"; fi;`$RAILS_ENV:\[\033[01;34m\]\w\[\033[00m\]\$ '

Here's what it looks like in action:

rails_terminal_prompt

I do most of my work in OSX 10.5, which uses GNU bash, version 3.2.17(1)-release (i386-apple-darwin9.0). I suspect this could be tweaked to work in more versions of bash.


Put some Swedish Chef in your Ruby app!

I wrote a Ruby port of a PHP class I found which will 'translate' English strings to Swedish Chef. I posted the Cheferizer code to GitHub a few days ago, so go crazy. Many thanks to Erik Bakker, the author of the encheferizer.php class I used as a model. He, in turn, gives credit to John Hagerman as the original author of the Chef-ing algorithm he implemented. All the URLs cited in that source code were dead, so I don't link to them here, but I am grateful for the inspiration. Maybe the whole world has moved beyond being entertained by silly stuff like this, but I sure hope not.

include 'cheferize'
class String
  include Cheferize
end

>> "This is a test!".to_chef
=> "Tees is e test, bork bork bork!"

Here's a slightly longer example of the time you can waste paying tribute to a personal hero... First the original English.

Cheferize is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

Cheferize is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Cheferize; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

And now, enter the Chef.

Cheffereeze-a is free-a sufftvere; yuoo cun redeestriboote-a it und/ur mudeeffy
it under zee terms ooff zee GNU Generel Poobleec Leecense-a es poobleeshed by
zee Free-a Sufftvere-a Fuoondeshun; ieezeer ferseeun 2 ooff zee Leecense, oor
(et yuoor oopshun) uny leter ferseeun.

Cheffereeze-a is deestribooted in zee hupe-a tet it veell be-a useffool,
boot VITOUT UnY VERRUnTY; veetuoot ifee zee impleeed verrunty ooff
MERCHUnTEBILITY oor FITNESS FOR E PERTICULER PURPOSE. See-a zee
GNU Generel Poobleec Leecense-a fur mure-a deteeels.

Yuoo shuoold hefe-a receeefed e cupy ooff zee GNU Generel Poobleec Leecense-a
elung veet Cheffereeze; iff nut, vreete-a tu zee Free-a Sufftvere-a
Fuoondeshun, Inc., 51 Frunkleen St, Feefft Fluur, Bustun, MA 02110-1301 USA

Read data in an ActiveRecord-based Rails session

Here's a simple method you can use in a console to determine the contents of an existing Rails session. All you need is the session id.

def read_session( sess_id )
  result = ActiveRecord::Base.connection.select_all( "SELECT * FROM sessions WHERE session_id = '#{sess_id}'" )
  Marshal.restore( Base64.decode64( result[ 0 ][ 'data' ] ) ) if result[ 0 ]
end

The return value will be a Hash, or nil if no session is found for that id.

Note this doesn't do any input-escaping, so it's open to SQL injection. Don't expose this code to users. (That's a good idea for lots of reasons, given what it does.)

Suppose you want to just watch a particular session in your console...

def report_session( sess_id )
  i = 0
  while true
    puts "#{i} : #{read_session( sess_id ).inspect}"
    i += 1
    sleep 1
  end
end

$ script/console
Loading development environment (Rails 2.2.2)
>> report_session 'a3fbc5de20723a242b54a73cad4221bb'
0 : {"flash"=>{}}
1 : {"flash"=>{}}
2 : {"flash"=>{}}
3 : {"flash"=>{}}
...

It'll keep updating with session data until you kill it with Control-c.

Automatic Per-Controller CSS in Rails

This is a simple method I've been using to automatically include controller-specific stylesheets. If you have app/controllers/users_controller.rb, then public/stylesheets/users.css will be included automatically if it exists. I'm sure this has been done before, but here's my take on it.

# app/helpers/application_helper.rb
module ApplicationHelper
  def controller_stylesheet
    controller_name = controller.controller_name
    if File.exists?( "#{Rails.root}/public/stylesheets/#{controller_name}.css" )
      stylesheet_link_tag( controller_name )
    end
  end
end

<!-- app/layouts/application.html.erb -->
<html>
  <head>
    <%= controller_stylesheet %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

Installing Darwin Calendar Server 2.3 on Ubuntu 9.10

Back in my original 'calendarserver on Linux' posting, I wrote about how to set up Apple's Darwin Calendar Server (DCS) on Ubuntu Linux. At the time, I neglected to mention that was Ubuntu 8.10. This turns out to be important, because I have since built a new server using Ubuntu 9.10 and discovered some important differences in the new Ubuntu.

The art of not losing things

My wife is better at finding things than I am. I am better at not losing things than she is. It's an important difference.

Being good at 'finding things' means she's more careful when she goes place to place looking for something. She notices details I don't. She thinks of places to look which don't occur to me.

Being good at 'not losing' things means I tend to put stuff back in the same place every time. Sara is constantly losing her keys, purse, or cell phone because she tends to drop them wherever, then go looking for them later. I tend to put stuff back in one place. (Notice I say *tend to*. I'm definitely not claiming any perfection here. I need her help plenty of times finding stuff I've stupidly dropped in some random place...) I developed the habit because, as mentioned above, I'm not very good at looking for things. This is my way of working around my own lack of search skill.

Whenever I have something in my hands which I no longer want to be holding, I tend to ask the question "where is the first place I'd look for this thing?" Whichever place first comes to mind is the place where I put the thing. Not perfect, but a lot better that before, when I combined the 'drop stuff anywhere' storage strategy and the 'carelessly and unproductively scan for things' search algorithm.

Why does this matter in the context of a blog about coding? I think the same rules about 'where to put things' apply really well to software or database design. 'How do I want to search for this?' should play a large part in 'how should I store this data?'.

Of course there are plenty of other concerns. For example, tailoring a database schema too closely to a single kind of search often reduces the ease with which you can perform other kinds of searches of that data. But 'how will I search for this stuff' should be *part* of the design process. And, if you can't answer that question at all, I think it's worth asking 'do I really need to store this data at all?'

Opting Out of Verizon's DNS Services

Got weird error trying to access www.google.com.

No Googles!

Co-worker helped me figure out this was Verizon's 'DNS Assistance' messing up.
http://www.verizon.net/central/vzc.portal?_nfpb=true&_pageLabel=vzc_help...

Tried their 'opt out' option. Visiting a non-existent domain brings up an incredibly lame error page. The page you see below is HTML copy/pasted from the standard Internet Explorer page (including image references to 'C:\...'), with some Verizon links slapped on the end of it. Wow.

Verizon DNS Assistance Fail.

What the heck?

I switched to 4.2.2.1 and 4.2.2.2, but there are plenty of other public DNS providers. This is kinda funny since 4.2.2.1 is also a Verizon server, but it doesn't have this annoying 'helpful' feature.

http://www.tech-faq.com/public-dns-servers.shtml


Our Smart President

Just read a story about the Obama administration using the Drupal CMS for whitehouse.gov. Maybe we can say they're learning from us here at Deanspot?

http://techpresident.com/blog-entry/whitehousegov-goes-drupal

http://www.drupal.org

Syndicate content