Jeff Dean's blog



Jeff DeanJeff Dean
DelegateClass rocks my world
edit Posted by Jeff Dean on Wednesday January 20, 2010 at 07:59PM

If you notice that your classes have more than one responsibility, you can easily split them up into multiple, more cohesive classes using Ruby's DelegateClass.

Jeff DeanJeff Dean
AutoTagger Bug Fixes
edit Posted by Jeff Dean on Monday October 26, 2009 at 08:36PM

If you are using AutoTagger, you may want to upgrade to the latest version. The following bug fixes were applied:

First, you can now define your stages as strings or symbols and auto-tagger will not fail (thanks to Chad Wooley for the bug report).

Next, when deploying from a branch auto_tagger uses real_revision, not the previous tag, to create the new tag thanks to Brian Takita.

Jeff DeanJeff Dean
ActiveHash is now much easier to test
edit Posted by Jeff Dean on Monday October 26, 2009 at 08:23PM

I recently released a new version of ActiveHash which adds a number of features that make it even easier to use Hash or Yaml data stores for ActiveRecord-esque models. The recent updates include:

  • Setters
  • belongs_to and has_many associations
  • save, create and destroy methods that add or remove the objects from the in-memory collection (great for object mother libraries like Fixjour)
  • support for string ids
  • support for hash-style yaml data (think Rails fixtures)
  • auto-incrementing ids by default (again, for Rails fixtures)

If you have earlier versions of ActiveHash I highly recommend that you upgrade. It makes testing and common uses much nicer. If you are on gemcutter, it's as simple as:

gem install active_hash

Enjoy!

I'm currently working on a large app where certain things have to happen when records are created, updated and deleted, such as:

  • Publishing to an activity feed
  • Generating emails
  • Adding entries to a changelog
  • Generating tasks and reminders

Further, the requirements state that admin users should be able to configure which of these actions happen for which objects in the system, who they go to, what the text is etc...

At first this looks like a great place for ActiveRecord Observers. However, after working with Observers there are a few things I dislike - namely that you can't easily apply observers to all of your models, and you can't selectively turn them on and off in tests. To remedy that problem, I created ActiveModelListener.

ActiveModelListener is a simple, global ActiveRecord event listener framework, using a middleware-esque architecture that can easily be turned on and off.

Jeff DeanJeff Dean
Standup 8/17: RubyMine rebase issues and Ruby truthiness
edit Posted by Jeff Dean on Friday August 21, 2009 at 09:25AM

Interesting Things

Truthiness

You can't make something "falsy" in ruby. For example, let's say you are a good Fowlerite and you are implementing a nil object pattern like so:

class User; end

class NilUser
  def nil?() true end
end

user = NilUser.new

if user
  puts "Access Approved"
else
  puts "Access Denied"
end

If you run that code, even though you've defined .nil? to be true, it will print "Access Approved". Ruby if/unless/else only recognize nil and false to be "falsey".

RubyMine rebase strangeness

When you rebase from the command line and get a merge error, then run the merge tool from RubyMine, the "Your changes" and "Their changes" will be the reverse of what you might think. If you are accustomed to clicking "accept theirs" to mean taking other people's changes, you'll be in for a surprise.

If you botch the git rebase, you can always go back with this awesome git command, brought to you by Peter Jaros:

git reset --hard "master@{ 1 }"

ActiveHash is a simple base class that allows you to use a ruby hash as a readonly datasource for an ActiveRecord-like model.

ActiveHash assumes that every hash has an :id key, which is what you would probably store in a database. This allows you to seemlessly upgrade from ActiveHash objects to full ActiveRecord objects without having to change any code in your app, or any foreign keys in your database.

It also allows you to use #belongs_to in your AR objects.

ActiveHash can also be useful to create simple test classes that run without a database - ideal for testing plugins or gems that rely on simple AR behavior, but don't want to deal with databases or migrations for the spec suite.

ActiveHash also ships with:

  • ActiveFile: a base class that will reload data from a flat file every time the flat file is changed
  • ActiveYaml: a base class that will turn YAML into a hash and load the data into an ActiveHash object

ActiveApi allows you to define a schema in Ruby, and use that schema to convert ruby objects to xml. An example looks like this:

Schema.version(:v1) do |schema|
  schema.define :article do |t|
    t.attribute :id
    t.string :title
    t.date :published_on
    t.has_many :comments
  end
end

Jeff DeanJeff Dean
Equality and sameness in Ruby
edit Posted by Jeff Dean on Monday June 29, 2009 at 06:43AM

Let's say you are building a leetspeak that deals with w00ts. You might write a class that looks like this:

class Woot
  def ==(other)
    true
  end
end

In theory, any Woot is equal to anything else:

puts Woot.new == Woot.new # true

You might think that with this setup, you could do something like this:

x = [ Woot.new ]
y = [ Woot.new ]
z = x - y

You might expect z to be an empty array in the case, but oh how wrong you would be. In the example above, the == is never called at all.

Jeff DeanJeff Dean
Sanitizing POST params with custom Rack middleware
edit Posted by Jeff Dean on Thursday June 11, 2009 at 04:48AM

The problem: Improperly escaped post data

I recently worked on an app that processed xml files. Once a week, a legacy system posted a large xml document to the app. For almost a year the app worked perfectly, and then we updated to rails 2.3.2 and the posts started failing spectacularly. Looking at the log files, I noticed that the params were incorrect:

<code>{"message"=>"hello", "xml"=>"<xml>Foo &amp", "Bar</xml>"=>nil, "action"=>"not_scrubbed", "controller"=>"examples"}</code>

After looking into it further, I realized that the data that was being posted contained semi-colons:

<code>xml=<xml>Foo %26amp; Bar</xml>&message=hello</code>

It turns out that rails used to only split params on ampersands, but that rack splits on both ampersands and semi-colons. We couldn't change the legacy system, so we had to remove the semi-colons before the post params got to rails.

The solution: Rack middleware

Using Rack middleware it's was easy to insert code before rails params parsing code executed. To start, build a class that conforms to the signature of a rack middleware layer, like so:

Jeff DeanJeff Dean
AutoTagger 0.9 released
edit Posted by Jeff Dean on Tuesday May 05, 2009 at 05:50PM

I'm happy to announce that AutoTagger 0.9 has been released thanks to Brian Takita and Mike Grafton. This resolves a few major issues and brings AutoTagger a big step closer to being ready for prime-time.

You can read more at http://github.com/zilkey/auto_tagger.

You can install the gem like so:

gem sources -a http://gems.github.com
sudo gem install zilkey-auto_tagger

Thanks Brian and Mike!

Other articles: