Ruby


25
Mar 12

Why I moved on from PHP

Alex Hudson has written a good piece on Zend Framework 2, and why he’s moving on from Zend Framework. I was an active contributor to Zend Framework from 2006 until 2008, and I moved on also.  In fact, I mostly moved on from PHP altogether, in large part directly because of Zend Framework.

I’d like to say it was because of the Java influence which is on its face largely at odds with the language it’s built on—but really, it was because I was tired of PHP and its ecosystem. I was tired of the weak typing (not dynamic typing), inconsistent function names, anything-goes argument orders, the generally poor quality of libraries and open source projects, the community values that led to both, the resulting difficulty in hiring good developers from that community… well, I could go on.

There were counterpoints to most of these arguments, and I made them to others. But eventually the weight of the problems added up, and I wanted options. Zend Framework seemed to be trying to turn PHP into Java, and although I hadn’t yet made a value judgment about Java I knew that wasn’t appropriate for PHP. It’s essentially a glue language like Perl, and the “PHP way” (such as it exists) is about lightweight, quickly-bootstrapped solutions. Otherwise, what is PHP good for?

At best, most developers see PHP as a hammer—not particularly fast or elegant, but it gets the job done.

Zend Framework highlighted these problems for me.  It served as a stark contrast to the quality of other PHP components, but exemplified the schizophrenic direction of PHP as a whole since 5.0 (PHP’s SPL—its Standard PHP Library—is every bit as Java-like as Zend Framework).

I glanced at Symfony and some other projects, but what I really wanted was something that addressed my complaints: strongly-typed, consistent, good libraries and community, etc. Professionally I began writing Java, both with and without frameworks like Spring and GWT. At home I began writing a lot of Ruby, using the MacRuby project to supplement some Cocoa I had already learned using Objective-C. I also played with Rails 2 and Merb.

The Java started off well enough—I was creating the same types of complex multi-tier applications that I did under PHP, but this time backed by static typing and a huge library of components from Spring and Apache. But even after I was up to speed, development was slower. I had always heard how Java was heavy, but now I truly experienced it: Spring, a “lightweight” alternative to Struts, had so much explicit (and, to my mind, pointless) infrastructure setup that I was thoroughly disillusioned with it within six months.

I had already blogged about why I thought writing JavaScript by proxy was a bad idea, but I was questioning all my assumptions and so I decided to explore GWT as well. In the end, my experience was similar to Spring—it was all too slow. In the case of GWT I felt both too far removed from the end result and occasionally too near (when I needed to jump into writing native JavaScript using JSNI). This leaky abstraction was explained as a fundamental design decision, but never sat quite right with me. I knew it was necessary, and that was the problem.

At the same time, I experienced none of these problems with Ruby. During this time of exploration I wrote a variety of things: a parser library for a non-trivial binary file format, some GUI components using MacRuby, a website in Rails 2, and an API in Sinatra. I started looking into Merb, but learned it was merging with Rails and so started becoming familiar with Rails 3 instead.

Contrary to my experience in both PHP and Java, I loved every moment writing Ruby. Like Python, it is both strongly- and dynamically-typed. I found the libraries to be generally high-quality, and when they weren’t, the authors tended to be up-front about that fact. The community, inspired by the Rails philosophy, was constantly pushing the envelope by embracing the latest and greatest, almost to a fault. It had a good community that valued pragmatic solutions.

It’s four years later now and I still love Ruby. It’s not the best solution for everything, so I’ve continued to learn new languages (my latest being Python), but it’s generally my first choice.

I still occasionally write some PHP at work. There’s a lot of sighing involved. Zend Framework has some good components and when appropriate I recommend it as a library. I wish it were more modular.

I wouldn’t recommend the MVC—it’s slow, and it places things in the way of routing that should probably go elsewhere. Zend Framework architect Matthew Weier O’Phinney is a smart guy, but he’s trying to drag the PHP community almost single-handedly toward the PHP-as-Java point of view. Frankly, I don’t think it’s right for the community and I don’t think the community is that interested. I predict Zend Framework 2.0 adoption will be glacial. Most people probably won’t ever bother making the switch.

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!

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!

9
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!