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.

Filtering for the Snippets category. Clear

Using dom_id with a presenter (or other objects)

by Ben

We have been using presenters much more often in our Rails code, with the goal of having views only use “Mustache-level” logic (conditionals, loops, and interpolation). We’ve been happy with the results so far; it really cleans up the views, and moves logic to easily testable objects. In fact, most tests for presenters can be fast specs and still test well.

I’ve gotten the impression that not everyone does presenters the same way, so before getting to the code I’ll clarify. Our presenters are decorator-like, with a restriction that they only transform values, not make any lasting changes to them. Methods are typically “opted-in” for use in the presenter using def_delegators from Forwardable. For a simple example, PersonPresenter might have a method called full_name that combines first_name and last_name; the Person class only manages the persistance of first_name and last_name. That is, presenters wrap an object with methods for presentation to a human.

Not all of Rails makes this pattern easy to use. We ran into an issue recently when calling dom_id() in a view. This was our code, roughly:

# File: app/presenters/foo_presenter.rb
class FooPresenter
  def initialize(foo)
    @foo = foo
  end

  def bar
    # ...
  end

  # ...
end

# File: app/controllers/foos_controller.rb
class FoosController < ApplicationController
  def show
    foo = Foo.find(params[:id])
    # It's nice to only have to expose a single object to the view.
    @foo_presenter = FooPresenter.new(foo)
  end

  # ...
end
# File: app/views/foos/show.html.erb
<span id="<%= dom_id(@foo_presenter) %>"><%= @foo_presenter.bar %></span>

And this is the error we got:

ActionView::Template::Error (undefined method `to_key' for #<FooPresenter:0x007fc782994a98>):
1: <span id="<%= dom_id(foo_presenter) %>"><%= foo_presenter.bar %></span>
[...]

The obvious fix would be to add a to_key method that just delegates to the model, but that quickly became a rabbit hole. Many more methods were needed, and I quickly gave up.

It turns out that dom_id() follows a protocol in that it will call to_model on whatever’s passed in. We can use that to solve our problem. (ActiveRecord objects just return self, as you might imagine.) Here’s the fix:

# File: app/presenters/foo_presenter.rb
def FooPresenter
  # ... (previous content)

  def to_model
    @foo
  end
end

Now the presenter can be used with dom_id(), delegating to the presented model. It’s a surprisingly simple solution. :)

(Versions: Ruby 2.0.0, Rails 3.2.12)

Filtering output when logging

by Ben

I needed to filter some output when logging. Unfortunately, the filtering built into Rails was no help because the logging wasn’t coming from parameters. It also wasn’t coming from a Hash. (To filter a Hash, you can also use ActionDispatch::Http::ParameterFilter.) Instead, it was coming from a value inside another object.

Although this wasn’t my final solution, I still think it could be useful to someone:

# License: MIT, GPLv2
module InspectionHelper
  def self.filter(object)
    def object.ai(*)
      '[AWESOME-PRINT-FILTERED]'
    end

    def object.inspect
      '[INSPECT-FILTERED]'
    end
  end
end

This will filter output from both inspect and the equivalent in awesome_print (which was the pain point for me earlier today).

Usage:

data = []
InspectionHelper.filter(data)
data.inspect # => '[INSPECT-FILTERED]'

# Or nested objects:
h = { something_important: Object.new }
InspectionHelper.filter(h[:something_important])
h.inspect # => {:something_important=>[INSPECT-FILTERED]}

Snippet: Play latest NBC Nightly News fullscreen

by Ben

This is the first of a series of posts about code I have in my GitHub repositories.

I’m often annoyed that I have to wait for iTunes to download the NBC Nightly News podcast so I can watch it in the morning. I also don’t like iTunes’ video player much — it’s slow and crashes all the time. (Why Apple hasn’t ported iTunes from Carbon to Cocoa is sometimes beyond me… but I’m sure it will happen eventually.)

Recently, I found out that NBC always publishes their podcast to the same location every day, so it was easy to make an AppleScript to open it in QuickTime X. QuickTime X starts playing it right away, without making me have to wait for it to download completely (or wait for iTunes to catch up with me).

It’s actually quite a simple script. Unfortunately, I couldn’t find a fullscreen verb for QuickTime X, so I had to use Jacob Rus’ menu_click method.

See more at my snippets repository on GitHub.

Download