Skip to main content

Benjamin Oakes

Photo of Ben Oakes

Hi, I'm Ben Oakes and this is my geek blog. Currently, I'm a Ruby/JavaScript Developer at Liaison. Previously, I was a Developer at Continuity and Hedgeye, a Research Assistant in the Early Social Cognition Lab at Yale University and a student at the University of Iowa. I also organize TechCorridor.io, ICRuby, OpenHack Iowa City, and previously organized NewHaven.rb. I have an amazing wife named Danielle Oakes.

NBC Quietly Discontinuing Video Podcasts

by Ben

UPDATE (2015-02-15): As of yesterday — Valentine’s Day of all days — the NBC podcasts are discontinued. The closest replacement I’m aware of is the PBS NewsHour YouTube Channel or PBS NewsHour Video RSS Feed (not a video podcast, unfortunately).

UPDATE (2015-03-05): The only remaining NBC video podcast is The Rachel Maddow Show, though they have limited it to a 25 minute selection of highlights. I would encourage you to show Rachel Maddow support for this. I doubt it’s a simple coincidence that she’s the only one still offering a video podcast.

I’ve been watching the NBC Nightly News video podcast for a long time. Probably since 2006, and maybe even as early as 2005 (ten years ago!). It’s never been perfect — sometimes they skip a day without explanation, and they clearly cut out some content on occasion — but it’s been an important part of how I’ve gotten news over roughly the last 10 years.

My wife and I will often watch it while eating breakfast together. We were greeted with this notice today:

Soon, this podcast will be discontinued, but you'll still be able to watch NBC Nightly News with Brian Williams, updated every evening, at nightlynews.com and the Nightly News app in the iTunes or Google Play Store. Nightly's audio podcast  will still be available.

NBC is dropping all their video podcasts, without explanation. They’re also dropping Meet the Press and Today alongside NBC Nightly News. MSNBC video podcasts, like The Rachel Maddow Show don’t have this notice yet, but I wouldn’t be surprised to see that happen. NBC isn’t the only one to drop their news video feeds; CBS and ABC seem to have dropped theirs a while ago. At the time of this writing, the last CBS Evening News video podcast is from early September 2014. I don’t know if others like PBS or BBC ever offered video podcasts, but I can’t find any remnant of them if they did exist.

All the audio podcasts remain. This move seems to be about video. That can be said for almost all major broadcasters, like ABC, BBC, CBS, CNN, NBC, and PBS. Seemingly no one is offering video podcasts.

So is NBC Nightly News stopping their video podcast really that big of a deal? Well, not specifically. My concern is really about the systematic reduction of the video podcast as a format.

Especially when I didn’t have a TV, I used to watch Nightly News on a laptop. Eventually, I added watching the podcast on a TV and my smartphone. It was (and is) great, because I could watch it whenever I wanted, often with breakfast the next morning. No waiting for downloading, no navigating extra menus. At one point, I even wrote a little Ruby script to automatically play it on my laptop in the morning. It was ready next to my coffee (which had also started automatically). There’s something nice about that.

That’s the thing about podcasts: they’re malleable. You can do so much with them. After all, a video podcast is just a file with a link to a DRM-free video file. There are very few restrictions to how a podcast consumer can use that file; you can play it on an old “unsupported” computer or your video game console. You can burn it to DVD. You can save segments you want to keep. You can use content in all sorts of interesting ways, moving it easily between devices. In the end, that’s probably exactly what NBC and other broadcasters don’t like about video podcasts.

The problem is, podcasts can’t really be replaced by websites and mobile apps. Those options force you to a specific interaction, a specific user experience. That’s much less interesting because those options are only useful to you if your usage happens to be one of the ones they considered and designed. To make it concrete, this means that you can’t watch this specific NBC content on your Apple TV, Roku, etc. anymore because NBC doesn’t want you to — although you could when it was a video podcast. Forcing the content through an app is a step backwards.

Marco Arment of Instapaper fame described this well when he wrote about RSS, the technology behind video podcasts:

This isn’t an issue of “openness”, per se — Twitter, for instance, has very good reasons to limit its API. You aren’t entitled to unrestricted access to someone else’s service. Those days are gone for good, and we’ll all be fine. We don’t need big web players to be completely open.

The bigger problem is that they’ve abandoned interoperability. RSS, semantic markup, microformats, and open APIs all enable interoperability, but the big players don’t want that — they want to lock you in.

[…]

RSS represents the antithesis of [vendor lock-in]: it’s completely open, decentralized, and owned by nobody, just like the web itself. It allows anyone, large or small, to build something new and disrupt anyone else they’d like because nobody has to fly six salespeople out first to work out a partnership with anyone else’s salespeople.

I can’t tell if video podcasts just didn’t get the traction in the market that they needed or if audio podcasts are just preferable because broadcasters really want to protect their video. The same could be said for terrestrial broadcasts (i.e., those you get for free over an antenna), which no longer seem to be a major priority for broadcasters either. I’ve considered getting a PVR to record video in lieu of video podcasts, but NBC isn’t available at our house (though several other stations are). Would we have been able to receive NBC here in the pre-cable era? I don’t know, but I wouldn’t be surprised if the answer were “yes.”

The entire television and online video industry is in a weird, transitory state right now. The number of options that used to be completely free and open are dwindling — even those that include advertisements. I don’t know if I’ll like how this transition ends, but in some ways, I can’t wait for the transition to be over.

Reactions

This Week in Google

(also available on YouTube)

This post was briefly featured on This Week in Google #285, starting at about 1:26:30 and running for about a minute. It didn’t get as much attention as exploding kittens, but hey, it’s the second time something I’ve done has been featured in a podcast. (The first was when Maid was on Ruby5.)

Twitter

Ruby Simple HTTP Server, minimalist Rake

by Ben

I use a really simple HTTP server all the time. It happens to be written in Python:

python -m SimpleHTTPServer 5000

That serves all the files in the current directory over HTTP on port 5000. Honestly, it works just fine, but I’ve always wondered if Ruby had an equivalent.

Here it is:

ruby -run -e httpd . -p 5000

(from Aaron Patterson’s tweet found via Zach Morek)

It’s pretty much the same, except it’s written in Ruby. More often than not, that’s not a big difference — except I can understand the code behind it.

#
# = un.rb
#
# Copyright (c) 2003 WATANABE Hirofumi <eban@ruby-lang.org>
#
# This program is free software.
# You can distribute/modify this program under the same terms of Ruby.

# [...]

##
# Run WEBrick HTTP server.
#
# ruby -run -e httpd -- [OPTION] DocumentRoot
#
# --bind-address=ADDR address to bind
# --port=NUM listening port number
# --max-clients=MAX max number of simultaneous clients
# --temp-dir=DIR temporary directory
# --do-not-reverse-lookup disable reverse lookup
# --request-timeout=SECOND request timeout in seconds
# --http-version=VERSION HTTP version
# -v verbose
#

def httpd
  setup("", "BindAddress=ADDR", "Port=PORT", "MaxClients=NUM", "TempDir=DIR",
        "DoNotReverseLookup", "RequestTimeout=SECOND", "HTTPVersion=VERSION") do
    |argv, options|
    require 'webrick'
    opt = options[:RequestTimeout] and options[:RequestTimeout] = opt.to_i
    [:Port, :MaxClients].each do |name|
      opt = options[name] and (options[name] = Integer(opt)) rescue nil
    end
    unless argv.size == 1
      raise ArgumentError, "DocumentRoot is mandatory"
    end
    options[:DocumentRoot] = argv.shift
    s = WEBrick::HTTPServer.new(options)
    shut = proc {s.shutdown}
    siglist = %w"TERM QUIT"
    siglist.concat(%w"HUP INT") if STDIN.tty?
    siglist &= Signal.list.keys
    siglist.each do |sig|
      Signal.trap(sig, shut)
    end
    s.start
  end
end

So how does it work? It’s actually a little surprising. Here’s the command again for reference:

ruby -run -e httpd . -p 5000

In order:

While that code is probably too clever, it’s nice to have a simple HTTP server wherever I have Ruby.

Even more, the concept is reusable:

# File: ake.rb
# Minimalist rake.  :)
def greet
  puts "Hello, #{ ARGV[0] }!"
end

Here’s the output

$ ruby -I . -rake -e greet Ben
Hello, Ben!
$ ruby -r ./ake -e greet Ben
Hello, Ben!

That could be a nice minimalist way to write some helper scripts without Rake or Thor.

All about to_h in Ruby 2.0

by Ben

I gave a talk at ICRuby today about Ruby 2.0, partially as a learning experience for myself. I hadn’t done much with Ruby 2.0 before, and I had fun learning more about what to expect. If you’d like to see what I presented, my slides are available.

A lot of what I showed about Ruby 2.0 was a pretty standard overview, but I paid special attention to to_h. I ended up doing some research that I haven’t seen written up elsewhere, and thought I should share it as a blog post as well.

What’s to_h?

It’s a new convention for retrieving a Hash representation of an object. When I was first learning Ruby in 2008, I remember expecting to_h to exist after learning about to_s for String and to_a for Array. In concept, it’s similar to serializable_hash in Rails as well. I’m happy to see this become a part of core Ruby.

What can I do with it?

Now that there’s an official method for getting the “Hash version” of an object, you can start to use it in your methods when using a Hash makes things easier, or you’d like to duck type.

Since to_h is now a part of Ruby’s core and std-lib, I thought I’d see how it’s used.

A quick word about the examples: we tend to use panda and bamboo as metasyntactic variables at Continuity Control, partially because of the great Jonathan Magen. Plus, they’re fun compared to plain old foo and bar.

Core

Searching ruby-doc.org core gave:

…and a handful of aliases called to_hash, which were also present in 1.9.

Here’s what they do:

ENV.to_h                 # => {"TERM"=>"xterm", "SHELL"=>"/bin/bash", ...}
{ panda: 'bamboo' }.to_h # => {:panda=>"bamboo"}
nil.to_h                 # => {}

s = Struct.new(:panda, :bamboo).new
s.to_h                   # => {:panda=>nil, :bamboo=>nil}

Std-lib

Searching ruby-doc.org std-lib gave:

I don’t have any examples for the latter 3, but OpenStruct#to_h is easy to demonstrate:

require 'ostruct'
os = OpenStruct.new(panda: 'bamboo')
os      # => #<OpenStruct panda="bamboo">
os.to_h # => {:panda=>"bamboo"}

Any gotchas?

Not everything about to_h works the way I’d expect.

Arrays

This doesn’t work:

%w(panda bamboo).to_h # => NoMethodError: undefined method `to_h'

I might have expected behavior like this:

Hash['panda', 'bamboo'] # => {"panda"=>"bamboo"}

That would be especially nice, since then you could convert back and forth from Array to Hash:

{ panda: 'bamboo' }.to_a.to_h # => NoMethodError: undefined method `to_h'

…but alas, that’s just not how it works. However, we can try to convince matz otherwise.

Something I found by accident: I screwed up Hash[] the first time and got a bunch of new warnings on STDERR.

Hash[['panda', 'bamboo']]
# (irb):5: warning: wrong element type String at 0 (expected array)
# (irb):5: warning: ignoring wrong elements is deprecated, remove them explicitly
# (irb):5: warning: this causes ArgumentError in the next release

In Ruby 1.9.3, it would print no warnings and simply return {}.

JSON

I also was hoping JSON would take advantage of to_h, since it’s now a part of Ruby’s stdlib.

require 'json'
JSON.generate(ENV)
# /usr/local/lib/ruby/2.0.0/json/common.rb:223:in `generate': only generation of JSON objects or arrays allowed (JSON::GeneratorError)
# from /usr/local/lib/ruby/2.0.0/json/common.rb:223:in `generate'
# from tmp/talk_code.rb:3:in `<main>'

I would have expected something like this:

require 'json'
# NOTE: This doesn't actually work this way.  Blog skimmers take notice!
JSON.generate(ENV) # => "{\"TERM\":\"xterm\",\"SHELL\": ...

Fortunately, you can do this:

require 'json'
JSON.generate(ENV.to_h) # => "{\"TERM\":\"xterm\",\"SHELL\": ...

…but that feels like an excellent use of to_h that should have been a part of JSON.

Enough complaining! Show something useful.

Duck typing is probably the most useful use case I can think of. It’s a good alternative to Hash[] in some cases as well.

to_h

Here’s a simple example. Let’s say I have a method called eat:

def eat(diet)
  "A panda eats #{ diet[:eats] }"
end

…but I want to make sure the diet that is passed in is treated like a Hash. That’s possible now:

def eat(diet)
  "A panda eats #{ diet.to_h[:eats] }"
end

# It works with a Hash
panda_diet = { eats: 'bamboo' }
eat(panda_diet) # => "A panda eats bamboo"

# ...a Struct
panda_diet = Struct.new(:eats).new('shoots and leaves')
eat(panda_diet) # => "A panda eats shoots and leaves"

# ...or even nil
eat(nil) # => "A panda eats "

Hash()

One other addition I noticed (but haven’t seen mentioned elsewhere) is the new Hash() method. It’s kind of like Array() or String() in Ruby 1.9.3 and below. These methods let you coerce values, in a sense.

Here’s an example using Array:

def eat_up(foods)
  # Turns anything into an `Array`:
  #
  #     nil        => []
  #     'bamboo'   => ['bamboo']
  #     ['bamboo'] => ['bamboo']
  #
  Array(foods).each do |food|
    puts eat(eats: food)
  end
end

eat_up(nil)
# [no output]
eat_up('bamboo')
# A panda eats bamboo
eat_up(['bamboo', 'shoots and leaves'])
# A panda eats bamboo
# A panda eats shoots and leaves

That’s actually very useful behavior; a lot of annoying type and error checking just goes away. Ever since I first saw Avdi Grimm present it, I’ve found many uses for it.

The good news is, you can now do something similar with Hash()

def eat(diet)
  diet = Hash(diet)
  "A panda eats #{ diet[:eats] }"
end

panda_diet = { eats: 'bamboo' }
eat(panda_diet) # => "A panda eats bamboo"
eat(nil) # => "A panda eats "

If used in the right situation, that might just be as useful as Array().

But strangely enough, Hash() doesn’t work exactly like to_h:

Hash([]) # => {}

Hash(OpenStruct.new)
# TypeError: can't convert OpenStruct into Hash
#     from (irb):100:in `Hash'
#     from (irb):100
#     from /usr/local/bin/irb:12:in `<main>'

I don’t currently have an explanation, but unless you need specific behavior from Hash(), you may prefer to use to_h.

Slightly less contrived examples

Flexible constructor

If you have a use case for it, to_h could make constructors more flexible:

class Panda
  def initialize(params)
    params = params.to_h

    @name = params[:name]
    @age = params[:age]
    @weight = params[:weight]
  end
end

Flexible constructor with OpenStruct

Or even use an OpenStruct instead, if you’d like:

require 'ostruct'

class Panda
  def initialize(params)
    params = OpenStruct.new(params.to_h)

    @name = params.name
    @age = params.age
    @weight = params.weight
  end
end

OpenStruct conversion

If you felt like it, you could even refactor that into this:

require 'ostruct'

# Convert to an `OpenStruct`
def OpenStruct(hash_like)
  OpenStruct.new(hash_like.to_h)
end

env = OpenStruct(ENV)
env.TERM # => 'xterm'

Reusable to_h definition

You could even parameterize how to define to_h:

# Related to my concept of `to_h` back in 2010: https://github.com/benjaminoakes/snippets/blob/master/ruby/to_h.rb
module ConversionHelper
  def pick(*methods)
    h = {}
    methods.each { |m| h[m] = send(m) }
    h
  end
end

class Panda
  include ConversionHelper

  attr_reader :name, :age

  def initialize(params)
    params = OpenStruct.new(params.to_h)

    @name = params.name
    @age = params.age
    @weight = params.weight
  end

  def to_h
    # Pandas are sensitive about their weight, after all...
    pick(:name, :age)
  end
end

I haven’t decided whether the last few ideas would actually be useful in practice, but these are the types of things that Hash() and to_h open up for Rubyists.

database configuration does not specify adapter

by Ben

From an answer I wrote for StackOverflow:

Another possible cause:

In Rails 3.2.x, establish_connection has a default argument set from the environment:

From connection_specification.rb:

def self.establish_connection(spec = ENV["DATABASE_URL"])
  resolver = ConnectionSpecification::Resolver.new spec, configurations
  spec = resolver.spec

The way ConnectionSpecification::Resolver works depends on ENV['DATABASE_URL'] giving a nil if not set. (Normally, it would be something like postgres://...).

So, if you happen to have misconfigured DATABASE_URL such that ENV['DATABASE_URL'] == '', that will give you database configuration does not specify adapter.

Debugging rsyslog and logrotate

by Ben

Takeaway: Debugging rsyslog and logrotate is easier when using Vagrant and logrotate‘s debug switch (-d).

I’ve been getting my hands greasy with more involvement in Ubuntu server maintenance lately, so I thought I’d share some of my experiences with debugging rsyslog and logrotate.

We’re using an EC2 instance running Ubuntu 12.04 (Precise Pangolin) to receive syslog packets from Heroku and elsewhere. They’re received with rsyslog, and we’re using logrotate to rotate and compress the log files. We’re being a little lazy right now and just letting everything go into /var/log/syslog. So far, that’s been a good choice as the machine only handles log aggregation. Most of the setup is similar to what Heroku recommends.

My first bump in the road was that which Ubuntu 12.04 doesn’t give rsyslog port 514 (the standard syslog port), unlike Ubuntu 10.04. This is because 514 requires root privileges. As a result, the port has to be above 1024, so I chose 1514 to make it easier to remember and know its purpose. It’s not completely clear why Ubuntu changed rsyslog to run under its own user (I would guess security reasons), but there is a bug report which helped me figure this out.

Following that I ran into an issue with getting logrotate to rotate the log files in the way we wanted. We decided that storing 30 days worth of logs, marking the rotation with the date, and compressing older logs would be best for our needs. It sounded easy enough to configure after looking at man logrotate and /etc/logrotate.conf. But it didn’t work! No matter what I tried, only 7 days of logs were retained, although compressing and adding a date extension worked fine.

It turned out to be a simple problem, but it’s more important to know how to debug these problems, I think. Below is what I did.

You probably don’t want to debug configuration problems directly on your production instance, or even on a staging instance. To develop the changes locally, I found that the easiest solution was to use Vagrant. They provide a precise64 box which was perfect for my needs:

vagrant box add precise64 http://files.vagrantup.com/precise64.box

From there, you can test logrotate with the -d switch. Point it to your configuration file and then see what it says it will do:

logrotate -d /etc/logrotate.conf

The problem behavior was clearly visible in the output; /var/log/syslog was only being kept for 7 days. Changes to /etc/logrotate.conf did not make a difference for the rotation count (but I could change to doing dateext). Around that time, started poking around in /etc/logrotate.d/, where I found /etc/logrotate.d/rsyslog.

This is the original configuration for /var/log/syslog:

/var/log/syslog
{
        rotate 7
        daily
        missingok
        notifempty
        delaycompress
        compress
        postrotate
                reload rsyslog >/dev/null 2>&1 || true
        endscript
}

After that point, it was simple to try my changes and retest using logrotate as above:

/var/log/syslog
{
        rotate 30
        daily
        # NOTE: `dateext` means you can rotate at **most** once a day.  Be cafeful setting it globally.
        dateext
        missingok
        notifempty
        delaycompress
        compress
        postrotate
                reload rsyslog >/dev/null 2>&1 || true
        endscript
}

The debug output then showed it would retain the logs for 30 days. Great! It was then a simple matter of installing the same configuration in production.

While the result is important, I think the bigger takeaway is a process I can use in the future. With Vagrant and logrotate -d /path/to/conf in hand, future configuration changes are easier to develop, test, and deploy.

Using Heroku with an external MySQL database

by Ben

We recently had a need to use Heroku with an external MySQL database. Thankfully, there was already a gem that solved the problem. However, it didn’t have that much by the way of documentation, so I wrote this up and contributed it to the author. Also, I added X.509 support, which we required.


NOTE: After my pull requests are merged, you should look to the main repository’s README which has a copy of the below.


Example: MySQL with a CA Certificate

In this example, we are setting up a connection to an external MySQL server using the default initializer.

What we have:

First, we configure Heroku with the appropriate environment variables:

# You may have to specify the app name or remote name here via --app or --remote, respectively
heroku config:add EXTERNAL_DATABASE_CA='ca-cert.pem'
heroku config:add EXTERNAL_DATABASE_URL='mysql://username:password@server/dbname'

By default, heroku_external_db looks for the CA cert in
config/ca, so we need to commit it:

mkdir -p config/ca
cp path/to/ca-cert.pem config/ca
git add config/ca
git commit -v # Using -v since we want to make sure the contents are what we expect (e.g. not a private key)

Additionally, we need the mysql gem in our Gemfile since we are setting up a MySQL server:

echo "gem 'mysql', '~> 2.8.1'" >> Gemfile
bundle install # Need Gemfile.lock too

Keep in mind that Heroku installs its own database.yml for Rails apps and we have to install pg as well. Unfortunately, shared databases are mandatory (but are free).

$ heroku addons:remove shared-database:5mb
-----> Removing shared-database:5mb from our-app... failed
 !     Shared databases cannot be removed

PostgreSQL may still be useful to you if, for example, you want to have feature toggles in a local database, but the main data kept externally. However in our case, it also means all developers will need MySQL and PostgreSQL running locally, which is unfortunate.

One workaround is only installing pg in production:

# File: Gemfile

# *Only* needed on production.
group :production do
  gem 'pg', '~> 0.11.0' # Regardless of whether you plan to use the database or not, Heroku requires you have 'pg' installed.
end

Then bundle like so:

bundle install --without production

With our gems updated, commit:

git commit -av # Commit Gemfile and Gemfile.lock

Another option may be overriding database.yml somehow, although it would add complexity. For more info, please see stackoverflow.com/questions/4204724/strategies-for-overriding-database-yml.

With our dependencies out of the way, we can move on to testing the connection.

If you are making a new application, you may wish to have a simple MVC for testing that the connection works. E.g., for a blog style application with posts do:

rails generate scaffold post
# NOTE you probably want to change the default "Post.all" to "Post.limit(5)" or something similar
git add .
git commit # ...
# Don't forget to set a default route, etc.

With all these changes committed, we can deploy to our Heroku app:

git push heroku master # Your remote may be different

Now, since we are connecting to an existing database, we don’t need to run any migrations. (Keep in mind that when sharing a database, it is best to have one authoritative source for migrations to live.) If in your situation you’re creating a new database, you may need to do that, run migrations, seed the database, etc at this point.

Open our-app.heroku.com and we should see our data. If you happen to run into a problem, please check the logs first:

heroku logs --tail # Again, you may need to specify an app

If you are having a problem, a good starting point is double checking your passwords, usernames, security settings, etc.

Example: MySQL with X.509

The process is very much the same as the above example, except two extra environment variables and files are required. Below are the extra steps.

What we have:

First, we configure Heroku with the appropriate environment variables:

heroku config:add EXTERNAL_DATABASE_CA='ca-cert.pem'
heroku config:add EXTERNAL_DATABASE_CERT='client-cert.pem'
heroku config:add EXTERNAL_DATABASE_KEY='client-key.pem'

By default, heroku_external_db looks for the files in config/ca, so we need to commit them:

mkdir -p config/ca
cp path/to/ca-cert.pem path/to/client-cert.pem path/to/client-key.pem config/ca
git add config/ca
git commit

The rest of the process is the same as in “MySQL with a CA Certificate”.

Reactions

ActiveRecord::ConnectionNotEstablished in Rails 3.1 on Heroku

by Ben

Other languages: 日本語

We have a simple application that doesn’t have an ActiveRecord dependency. It’s deployed to Heroku, and it’s been working fine on Rails 3.0.x since April 2011. We knew we weren’t using ActiveRecord for database connectivity, but we let it be, since it wasn’t causing any issues.

When upgrading to Rails 3.1, we found that every single page would give ActiveRecord::ConnectionNotEstablished on our staging environment on Heroku. The same error didn’t happen in development. Although we might have been able to get gem 'pg' set up and working, we really didn’t need an ActiveRecord dependency at all.

I found part of a solution on StackOverflow, but it needed a little tweaking for Rails 3.1.0.

# File: config/application.rb

# Pick the frameworks you want:
# require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"

That’s what Rails 3.1.0 generates when running rails new myproject --skip-active-record. (Note that require "active_record/railtie" is commented out.) This solved our ActiveRecord::ConnectionNotEstablished problem, but gave us a few others, namely:

Fixtures

There’s some normal stuff to get rid of in terms of spec_helper.rb and/or test_helper.rb. Here’s an example:

# File spec/spec_helper.rb

# # If you're not using ActiveRecord, or you'd prefer not to run each of your
# # examples within a transaction, remove the following line or assign false
# # instead of true.
# config.use_transactional_fixtures = true

You may have others. Tarantula had to be adjusted for us, for example.

ActiveRecord::RecordNotFound

ActiveRecord::RecordNotFound, however, was an interesting problem. Everything worked fine without ActiveRecord except the places where we were using ActiveRecord::RecordNotFound to give a HTTP 404 to the user agent. That seems strange in a lot of ways, because a 404 shouldn’t have anything to do with your chosen ORM. My first intuition was to do require 'active_record/errors' (see also the Rails docs), but that caused problems with assumptions in 'rspec/rails'.

Right now, the below is what we ended up with:

# File: config/application.rb

# Pick the frameworks you want:
# require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"

# For errors like ActiveRecord::RecordNotFound
require "active_record"

Our automated tests (Rspec, integration tests, Tarantula, Selenium, etc) all pass with it and we no longer get ActiveRecord::ConnectionNotEstablished, but we still have an ActiveRecord dependency I don’t like. (There must be another error we can raise — I don’t entirely like the render '/404.html', status: 404 solution for several reasons.)

Update:

This blog post has been translated/incorporated into a Japanese blog post.

Reactions

WebKit-specific CSS rules (or hacks, if you prefer)

by Ben

There are many things about WebKit-based browsers like Chrome and Safari that I really like. One of them is the file selector widget; I’ve grown so used to being able to drag-n-drop files onto the control to upload that I really miss it when I use Firefox, IE, or when the developer decided to only give a Flash-based file uploader. It’s definitely saved me hours in poking around in my files.

Even though I think the widget is great usability-wise, it only really looks good on light backgrounds. It’s completely impossible to tell what file you’re uploading if the widget is on a black background:

That’s definitely not the case in Gecko (Firefox, etc.) or Internet Explorer. They don’t give the same readability problems on a dark background.

What can you do about it?

Well, it turns out you can target WebKit-based browsers with a relatively simple media query. Conceptually, it’s similar to using a conditional comment to have an “IE-hacks” stylesheet.

In that spirit, I decided to make a webkit.css file with WebKit-only rules. Given the support of media queries across browsers and the WebKit-specific -webkit-min-device-pixel-ratio, the following makes it possible to give CSS that only affects WebKit.

Within <head> add:

<link href="webkit.css" media="screen and (-webkit-min-device-pixel-ratio:0)" rel="stylesheet" type="text/css" />

Or, if you don’t want a separate file, you can avoid that by embedding the rule into an existing stylesheet like so:

@media screen and (-webkit-min-device-pixel-ratio:0) {
  /* Your CSS */
}

Within <head> add:

Then, to style all the background colors so that <input type="file" /> is readable, you can do something like this:

webkit.css

input[type="file"] {
  background-color: white;
  padding: 3px;
  -webkit-border-radius: 7px;
}

That’s simple enough to fix all file inputs in WebKit, but IE 6, 7, 8 and Firefox continue to work the same way.

Here’s the result:

Reactions

Rails Timezones

by Ben

I ran into a Rails 3.0.1 timezone issue today that I didn’t see discussed many other places.

Basically, I just want to have a page in my app that shows the time in different time zones. That seems simple and something tailor suited for timezone support.

I started with this:

>> Time.now.in_time_zone('EST')
=> Tue, 23 Nov 2010 11:09:42 EST -05:00

Okay, so far so good. Next:

>> Time.now.in_time_zone('PST')
NoMethodError: undefined method `period_for_utc' for nil:NilClass
[...]
>> Time.now.in_time_zone('CST')
NoMethodError: undefined method `period_for_utc' for nil:NilClass
[...]

Wait, that’s odd… why doesn’t that work? After searching, I found you could use some city names like so:

>> Time.now.in_time_zone('Tokyo')
=> Wed, 24 Nov 2010 01:04:54 JST +09:00

But of course JST won’t work:

>> Time.now.in_time_zone('JST')
NoMethodError: undefined method `period_for_utc' for nil:NilClass
[...]

And neither will major American cities:

>> Time.now.in_time_zone('New York')
NoMethodError: undefined method `period_for_utc' for nil:NilClass
[...]
>> Time.now.in_time_zone('Chicago')
NoMethodError: undefined method `period_for_utc' for nil:NilClass
[...]

Nothing too relevant came up when I googled the above errors and phrases (part of why I’m posting this), but then I came across the rake time:zones:us and rake time:zones:all Rake tasks. They list valid timezones for you.

The thing that gets me is that 'EST' and 'Tokyo' work as expected, but 'PST' and 'New York' don’t. These are what I ended up with:

>> Time.now.in_time_zone('Eastern Time (US & Canada)')
=> Tue, 23 Nov 2010 11:08:12 EST -05:00
>> Time.now.in_time_zone('Central Time (US & Canada)')
=> Tue, 23 Nov 2010 10:06:08 CST -06:00
>> Time.now.in_time_zone('Pacific Time (US & Canada)')
=> Tue, 23 Nov 2010 08:06:23 PST -08:00

Ironically, it lists EST, CST, and PST in the results. It’s still confusing to me why the longhand version is the preferred notation here (sometimes), but at least you’re given the tools to look it up.

Like always, let me know if this post helps you through an error. We’re all in this together.

Update: The good people over at Airbnb found this post helpful when upgrading from Rails 2.3 to 3.0. I’m glad it helped you out!