23
Dec 11

Restarting Pow when DNS stops responding

I love Pow, the Rack-based development web server from 37signals, but one thing I can’t stand is how sometimes it stops responding to DNS for no reason in particular.

Well, Mike Sutton figured out how to fix it, and I turned it into a Bash script. Just save this as pow-restart (or whatever) and run it whenever you start having issues:

#!/bin/bash
# Restarts Pow when DNS fails to resolve
lsof | grep 20560 | awk '{print $2}' | xargs kill -9
launchctl unload ~/Library/LaunchAgents/cx.pow.powd.plist
launchctl load ~/Library/LaunchAgents/cx.pow.powd.plist
Like this post? You might also like Coalmine, my centralized error tracking service for your apps. Coalmine captures errors and all kinds of helpful debugging information, notifies you, and makes it all searchable. Check it out!

21
Sep 11

Testing routes with Rails 3.1 engines

Either I’m doing something wrong, or there’s a bug with Rails 3.1 engine routes and route tests.

The problem is that tests like these don’t seem to work when dealing with an engine with the follow RSpec test (the engine name is “Magic” in this case):

describe Magic::PoniesController do
describe "routing" do
it "routes to #index" do
get("/magic/ponies").should route_to("magic/ponies#index")
end
end
end

Well, there are actually two problems, the second being that the path helpers aren’t available to the engine’s specs.

The routes are declared like this:

Magic::Engine.routes.draw do

Instead of like this:

Rails::Application.routes.draw do

And for some people, just changing that is enough—it imports those routes directly into the parent application root path. But I’m wanting an isolated engine that can be mounted in the parent application like this:

Rails.application.routes.draw do
mount Magic::Engine => "/rainbow"
end

Of course, there’s a fixed mount of “/magic” in the engine’s dummy application, so that we can test it effectively.

What’s the solution? Well, Jason Hamilton and I (but mostly him) have come up with a solution that basically just copies the engine routes into the application routes on an as-needed basis.

Here is Jason:

OK, so throw this in your engine lib and require it in the engine.rb:

module Magic
module Rails
module Engine
##
# Automatically append all of the current engine's routes to the main
# application's route set. This needs to be done for ALL functional tests that
# use engine routes, since the mounted routes don't work during tests.
#
# @param [Symbol] engine_symbol Optional; if provided, uses this symbol to
# locate the engine class by name, otherwise uses the module of the calling
# test case as the presumed name of the engine.
#
# @author Jason Hamilton (jhamilton@greatherorift.com)
# @author Matthew Ratzloff (matt@urbaninfluence.com)
def load_engine_routes(engine_symbol = nil)
if engine_symbol
engine_name = engine_symbol.to_s.camelize
else
# No engine provided, so presume the current engine is the one to load
engine_name = self.class.name.split("::").first.split("(").last
end
engine = ("#{engine_name}::Engine").constantize

# Append the routes for this module to the existing routes
::Rails.application.routes.disable_clear_and_finalize = true
::Rails.application.routes.clear!
::Rails.application.routes_reloader.paths.each { |path| load(path) }
::Rails.application.routes.draw do
resourced_routes = []

named_routes = engine.routes.named_routes.routes
unnamed_routes = engine.routes.routes - named_routes.values

engine.routes.routes.each do |route|
# Call the method by hand based on the symbol
path = "/#{engine_name.underscore}#{route.path}"
verb = route.verb.to_s.downcase.to_sym
requirements = route.requirements
if path_helper = named_routes.key(route)
requirements[:as] = path_helper
elsif route.requirements[:controller].present?
# Presume that all controllers referenced in routes should also be
# resources and append that routing on the end so that *_path helpers
# will still work
resourced_routes << route.requirements[:controller].gsub("#{engine_name.downcase}/", "").to_sym
end
send(verb, path, requirements) if respond_to?(verb)
end

# Add each route, once, to the end under a scope to trick path helpers.
# This will probably break as soon as there is route name overlap, but
# we'll cross that bridge when we get to it.
resourced_routes.uniq!
scope engine_name.downcase do
resourced_routes.each do |resource|
resources resource
end
end
end

# Finalize the routes
::Rails.application.routes.finalize!
::Rails.application.routes.disable_clear_and_finalize = false
end
end
end
end
end

Rails::Engine.send(:include, Magic::Rails::Engine)

Call it whatever you like. I should probably create a gem for it, but ehhh… I think this will get fixed soon enough.

Anyway, in your spec_helper.rb (or test_helper.rb) call it like this:

Magic::Engine.load_engine_routes

Ta-da! Tests are passing, children are singing, and all is right with the world.

This post has been updated to fix named route handling.

Like this post? You might also like Coalmine, my centralized error tracking service for your apps. Coalmine captures errors and all kinds of helpful debugging information, notifies you, and makes it all searchable. Check it out!

09
Feb 11

Getting rake db:seed and config.threadsafe! to play nice

If you’ve enabled config.threadsafe! in your Rails production environment, the chances are good that you’ll encounter a confusing “uninitialized constant” error when you try to seed your database using rake db:seed.

The fact is Rails’ thread safety mode does not work with rake db:seed. No need to disable this option entirely, though. With a small modification to your environment and a simple Rake task, you’ll be good to go.

# config/environments/production.rb

# Enable threaded mode
config.threadsafe! unless ENV['THREADSAFE'] == 'off'
# lib/tasks/threadsafe.rake

namespace :threadsafe do
# desc 'Enable thread-safe mode (enabled by default in production)'
task :enabled do
ENV.delete 'THREADSAFE'
end

# desc 'Disable thread-safe mode'
task :disabled do
ENV['THREADSAFE'] = 'off'
end
end

# Ensure we are always running in single-threaded mode for Rake tasks
Rake::Task['environment'].prerequisites.insert(0, 'threadsafe:disabled')

We’re using an environment variable to tell our application whether we want to enable threaded mode or not, then disabling for all tasks that depend on the Rails environment. You can also specify it manually on the command line if you prefer that instead of making it a dependency for :environment (e.g., RAILS_ENV=production rake threadsafe:disabled db:seed).

Like this post? You might also like Coalmine, my centralized error tracking service for your apps. Coalmine captures errors and all kinds of helpful debugging information, notifies you, and makes it all searchable. Check it out!

13
Dec 10

Mountable engines in Rails 3.1 beta: getting started


Photo courtesy Tambako the Jaguar.

As Rails matures, it’s becoming more and more common to see it powering large-scale applications with many moving parts. These can be a chore to maintain in any framework, but a reusability mechanism can make all the difference in the world, if only so you can break code into mentally digestible areas.

Until recently, Rails lacked a recommended way to tackle this. Plugins didn’t do the job, and engines weren’t officially supported. Without that support, it was difficult to justify making them a fundamental dependency of your application. Of course, engines were the way to go in the end, and in Rails 3 they were finally merged into Rails itself.

There are still a few speed bumps for engines in the current version (at the time of writing, 3.0.3). Luckily, Piotr Sarnacki devoted his summer to improving engine support and has done a fantastic job bringing us closer still to true mountable applications. So let’s try it out!

By the end of this article, you should have a functioning application and engine running on edge Rails (3.1 beta). We’ll cover the other aspects of this in a future article, but this will get you up and running.

The road to bundle install

In this first section, we just want to do enough to get our first bundle install going.

Let’s create our main application and the engine.

rails new papa_bear
rails new baby_bear

Now we’ll need a gem specification. Bundler has a command for this, but first we’ll need to get rid of the Gemfile that Rails created. We’re also going to update Bundler to ensure that the bundle gem command works how we want it to—it fails with older versions.

rm baby_bear/Gemfile
sudo gem update bundler
yes | bundle gem baby_bear

The last command pipes bundle gem through yes, automatically overwriting the Rakefile and .gitignore files (we don’t need the original versions).

Now you need to declare a dependency on baby_bear from papa_bear. In papa_bear/Gemfile, add the following line:

gem 'baby_bear', :path => '../baby_bear'

By default, Rails assumes you want to depend on the version of Rails that you used to create the application. We want to use edge Rails, so we’ll have to change that.

Remove this line from papa_bear/Gemfile:

gem 'rails', '3.0.x'

Then replace it with these lines:

gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'arel', :git => 'git://github.com/rails/arel.git'
gem 'rack', :git => 'git://github.com/rack/rack.git'

(Edge Rails depends on edge Arel and edge Rack, also—release versions won’t cut it.)

For completeness, we should also be explicit that the baby_bear gem depends on Rails. For this, we can’t explicitly depend on Git (as we can in papa_bear’s Gemfile), but we should at least make the dependency meet 3.0. Since papa_bear’s Rails dependency satisfies baby_bear’s, this should be fine.

Add this to baby_bear.gemspec:

s.add_dependency 'rails', '>= 3.0.0'

Alright, we’re ready to go!

cd papa_bear
bundle install

And our dependencies are installed.

Keep in mind that when working with engines, you only ever need to run bundle install from the main application. It pulls in all the engines’ required gems.

Also, be sure not to run the last command as sudo.

Onto rails server

Because the engine isn’t a complete app, we can get rid of some configuration to reduce confusion.

cd ../baby_bear
rm config/application.rb
rm config/boot.rb
rm config/database.yml
rm config/environment.rb
rm -rf config/environments
rm -rf config/initializers

In papa_bear/config/routes.rb, add this line within the main block:

mount BabyBear::Engine => '/baby-bear'

There isn’t actually a BabyBear::Engine right now, but before we create it let’s make sure we remove any references to BabyBear::Application. If you’ve been following the instructions, this should only be in baby_bear/config/routes.rb. Replace BabyBear::Application.routes.draw with BabyBear::Engine.routes.draw.

Now the engine. In baby_bear/lib/baby_bear.rb, add the following line at the top:

require 'baby_bear/engine'

Then create baby_bear/lib/baby_bear/engine.rb from this template:

require 'rails'

module BabyBear
  class Engine < Rails::Engine
  end
end

We have a choice at this point: either we can namespace all of our engine’s application classes (controllers, models, etc.)—or not. Namespaces help prevent naming conflicts between your engine and the main application, and frankly, if you’re going to the trouble of developing an engine, you probably care about separation of responsibilities and reusability already. In any event, this tutorial will use namespaces.

So let’s add the following line to BabyBear::Engine:

isolate_namespace BabyBear

This creates a little more work for us up front because we’ll have to move our controllers, helpers, mailers, models, and views into their own baby_bear subdirectories.

mkdir app/controllers/baby_bear
app/helpers/baby_bear
app/mailers/baby_bear
app/models/baby_bear
app/views/baby_bear
mv app/controllers/application_controller.rb app/controllers/baby_bear/
mv app/helpers/application_helper.rb app/helpers/baby_bear/

Be sure to change ApplicationController to BabyBear::ApplicationController. Ditto for ApplicationHelper.

In order to make sure that the engine is running normally, we’ll need to create a page to test it. This is a good time to give you the bad news: engines can’t use the rails command. Sorry, no code generation for baby_bear. In practice, I’ve found that the benefits of engines outweigh this (rather disappointing) drawback, however.

touch app/controllers/baby_bear/index_controller.rb
mkdir app/views/baby_bear/index
touch app/views/baby_bear/index/index.html.erb

Here’s the controller…

module BabyBear
  class IndexController < ApplicationController
    def index_action
    end
  end
end

…and its corresponding view.

It works!

One last thing: we need a route. Add the following line to baby_bear’s config/routes.rb, in the main block:

root :to => 'index#index'

Finally, we’re ready to start WEBrick.

cd ../papa_bear
rails server

Are you ready for this?! Go to http://localhost:3000/baby-bear.

Finally, success! Hopefully, anyway. If not, be sure to double-check your steps and check out the code linked below. Good luck!

Download the code.

Like this post? You might also like Coalmine, my centralized error tracking service for your apps. Coalmine captures errors and all kinds of helpful debugging information, notifies you, and makes it all searchable. Check it out!

02
Dec 10

Git bisect is the best thing ever

I’ve raved about this command to coworkers before, but this morning after a bundle install with edge Rails our multi-database migrations broke, and I needed to figure out why. This had happened sometime between November 15 and December 2… on a less active codebase that might not be a big deal, but there were 204 commits to Rails in that time.

Enter git bisect!

$ cd rails/
local:rails matt$ git bisect start
local:rails matt$ git bisect bad
local:rails matt$ git bisect good 8124b2bc24b8312ee4d1ce2f133bf6e2dd87ad49
Bisecting: 204 revisions left to test after this (roughly 8 steps)
[51007f1dbafe029ed85b2a296736a00e6b24ec58] Previous version inaccurately suggested that
local:rails matt$ git bisect bad
Bisecting: 101 revisions left to test after this (roughly 7 steps)
[77440ec51ad28a7e63651f0976053584a7f58768] fixing assertions so error messages will be more helpful
local:rails matt$ git bisect good
Bisecting: 50 revisions left to test after this (roughly 6 steps)
[96b50a039276b4391ddf07b0a74850ce7bad6863] IrreversibleMigration is raised if we cannot invert the command
local:rails matt$ git bisect bad
Bisecting: 25 revisions left to test after this (roughly 5 steps)
[56c5820458fd3981161393c285cce67fdf35e60b] use shorter form for sql literals
local:rails matt$ git bisect bad
Bisecting: 12 revisions left to test after this (roughly 4 steps)
[f14c2bf58204f488cbe589e077a124865ea595f5] Pass the view object as parameter to the handler. Useful if you need to access the lookup context or other information when compiling the template.
local:rails matt$ git bisect bad
Bisecting: 5 revisions left to test after this (roughly 3 steps)
[974ff0dd43826aa375417852356ceede1bd24cf2] singleton method added is no longer needed
local:rails matt$ git bisect bad
Bisecting: 2 revisions left to test after this (roughly 2 steps)
[fe2f168d40385a0412f41c1a2a44a5536cada8df] fix warning during test execution
local:rails matt$ git bisect good
Bisecting: 0 revisions left to test after this (roughly 1 step)
[0bea9fd6be1c82154d7b2d4adbfc690a2c1df297] schema migrations work as instances
local:rails matt$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[8b2f801ed8690dcbc61d62e6b3518efaac70a4a4] converted migrations to support instance methods
local:rails matt$ git bisect bad
8b2f801ed8690dcbc61d62e6b3518efaac70a4a4 is the first bad commit
commit 8b2f801ed8690dcbc61d62e6b3518efaac70a4a4
Author: Aaron Patterson <aaron.patterson@gmail.com>
Date:   Wed Nov 17 12:53:38 2010 -0800

    converted migrations to support instance methods

:040000 040000 8e4adf421f6b9d8e6d696ac9526319b8e71bb486 cf3def12c0e5c1e92393f7293a5c5c9637d5af8f M  activerecord

If it’s a relatively simple bug to isolate, look into git bisect run–it makes the process entirely automated.

(Oh, and by the way, if anyone is running into the same problem I did, ActiveRecord::Base.connection is now ActiveRecord::Base#connection. In other words, it’s now an instance method, not a class method.)

Like this post? You might also like Coalmine, my centralized error tracking service for your apps. Coalmine captures errors and all kinds of helpful debugging information, notifies you, and makes it all searchable. Check it out!