Category Archives: Midnight Hour Brewery

Brewing and such

Creativespace ESB

I made 10 gallons of a simple ESB today, and it turned out fine. The ingredients came from Austin Homebrew Supply.

Fermentables

  • 17 lbs Maris Otter Pale
  • 1.5 lbs Crystal 60L

OG 10.75° Plato

Hops

  • 2 oz 7.7% AA Brewer’s Gold (60 mins)
  • 2 ox 4.5% AA Yakima Goldings (15 mins)

Est 41.8 IBU

White Labs WLP002 English Ale yeast

What went well:

  • Brewday was quite smooth. I now have a great grasp of how my equipment works together and how to fit brewday tasks into the downtime between hop additions and mash stirrings.
  • I verified that water loss in my mash tun is acceptably small — less than half a gallon. I wondered about losses here because my manifold is not sweated together meaning that suction could be lost before collecting all the sweet wort.
  • I got about 65% efficiency out of my system, which is better than usual. I did a little better on the SG than suggested by Austin Homebrew.
  • The hand-drill paint stirrer is just awesome for aerating wort.

Concerns include:

  • The pitchable tube spent a day in the Texas heat because UPS doesn’t knock very loud. It smelled a little funky when I opened it, but the starter was better.
  • I did not chill down to an ideal temperature before pitching. Threw the yeast into about 95° F wort. The fermenter is in a nice cool room now and I think the wort is cooler than last time.

For my readers looking for an update on the duck-in cooler, I made little progress since the last post. Too much weekend traveling. After the Longshot Competition judging this weekend, though, I will have time to finish it.

–Dean

Here is Proof My Wife Loves Me and Wants Me To Be Happy

With apologies to Ben Franklin.

My last beer fermented a little too warm and turned out full of esters. What I am calling The Fruity Brit is still drinkable as demonstrated last night when Adie and I had eight friends over for pizza and beer. The first keg is at least three gallons light. A good time was had by all, even without chairs.

The Fruity Brit is light on hops and body. I can pretend there is a clean malt profile, but the fermentation flaws overpower that. However, I hit the alcohol content right on the button: non-offensive. The Brit’s gravity bottomed out at 4° brix falling from 6°, putting it at about 2.3% ABV. Next time I will start and end higher, and throw in more hops for good measure. My objective is to zero in on a medium-bodied, lightly hopped British session beer.

While gatherings of friends will continue, I do not anticipate unaided fermentations to turn out any better. As summer approaches, Texas ain’t getting cooler. In Redwood City I had a chest freezer with good control over bubbling carboys, but now I have fifteen gallon conicals towering four feet tall on PVC stands. Such things just do not fit in this sort of chest freezer. A proper stand-up freezer runs around $500 and Craig’s List here is pretty pathetic. Those stand-up freezers only fit one of my fermenters, but I expect to be brewing with increasing frequency.

Three weeks ago I started working on a walk-in cooler that could accommodate both my fifteen gallon conicals. Many entwined brewers might meet steep resistance from their significant others, but my beautiful wife simply smiled and told me what a great idea it was. My initial estimate for materials was two hundred dollars easy, but I will probably go over by around fifty percent. While I may get a grimace from Sweetie, I know she will support me. It makes me all warm and fuzzy thinking of how much she must love me.

To drive the cooler I have a window air conditioner (which I wanted to leave in Cali, but Adrienne insisted we keep it; how smart). Here is how my cooler starts; left to right, the frame for the bottom and top.

Basic dimensions are 4×2 and 5 feet high. The skeleton is mostly finished 2×2 furring strips with a few 2×4 studs in key places. Here it stands loose fit together.

For insulation I am using reflective bubble wrap insulation stapled to the exterior plywood:

Followed by loose-fill insulation.

Then a semi-rigid plastic interior layer glued and stapled to the frame (see below). The floor gets a layer of plywood under the plastic to support the weight of the fermenting beer. Here is a shot of the bottom corner, the frame nailed to the floor.

Today a friend, Clay, and I made a lot of progress on the cooler. He is an electrician and offered to wire up an outlet, switch and light fixture. With these features, the project goes to way-cool.

Here is the back. The large opening is the AC mount. Clay is putting the light switch in center-top in our make-shift wiring box. All of the standard-type electrical bits and bobs are made for 2×4 studs while my walls are one and three-quarters thick, so we have to be creative.

Here is Clay again working on the light fixture. It is slightly too deep for the ceiling so we shimmed it out, taking advantage of the flexible plastic to hide the protrusion. We filled this with insulation and covered in plywood.

I will get some pictures of the interior up soon. When it is done I will break down the cost of materials. Expect a second follow-up when the thing is working.

In parting, I would like to thank Adrienne for allowing this project to take up my time, our money and her “pretty living room” for three weeks, going on six. I love you sweetie.

–Dean

Extending acts_as_commentable

acts_as_commentable is a nice little ruby on rails plugin. It extends your ActiveRecord classes giving them comments. We are going to use comments on all kinds of things, starting with recipes, of course. However, AAC lacks a critical feature: the ability for users to approve comments before they are displayed. In this post I am going to run through extending AAC using acts_as_state_machine.

The first thing I did (and do to all the plugins we use) was pistonize the plugin so I could hack on it without fear of getting my changes destroyed.

I start off simply here by adding two states to the Comment model: :pending and :approved.

class Comment < ActiveRecord::Base
  # The first element of this array is the initial state
  VALID_STATES = [ :pending, :approved ]
  acts_as_state_machine :initial => VALID_STATES[0]
 
  event :approve do
    transitions :from => :pending, :to => :approved
  end
 
  VALID_STATES.each do |_state|
    # Define _state as a state
    state _state
  end
 
  # More code snipped
end

Now we are going to write some real code, so here comes a little RSpec. aac provides three class methods:

class Comment < ActiveRecord::Base
  class << self
  # Helper class method to lookup all comments assigned
  # to all commentable types for a given user.
  def find_comments_by_user(user)
 
  # Helper class method to look up all comments for
  # commentable class name and commentable id.
  def find_comments_for_commentable(commentable_str, commentable_id)
 
  # Helper class method to look up a commentable object
  # given the commentable class name and id
  def find_commentable(commentable_str, commentable_id)
  end

Since it didn’t come with Test::Unit or RSpec tests I wrote up some test for these methods.

describe Comment, "class methods" do
  fixtures :comments, :recipes, :users
  it "should find comments by user" do
    Comment.find_comments_by_user( comments(:comment_one).user ).should all_belong_to( comments(:comment_one).user )
  end
 
  # This could be more specific
  it "should find comments for a particular class" do
    Comment.find_comments_for_commentable( Comments(:comment_one).commentable_type, comments(:comment_one).commentable_id ).should be_an_instance_of(Array)
  end
 
  it "should find all comments for a particular class" do
    # I happen to know that comment_one is a recipe comment
    Comment.find_commentable( "Recipe", comments(:comment_one).commentable_id ).should be_an_instance_of(Recipe)
  end
 
end

If you are confused by should all_belong_to then you should check out my previous post. With these specs out of the way we can go on to adding more new code.

  it "should find approved comments by user" do
    Comment.find_approved_comments_by_user( comments(:comment_one).user ).should all_be_in_state("approved")
  end
 
  it "should find pending comments by user" do
    Comment.find_pending_comments_by_user( comments(:comment_one).user ).should all_be_in_state("pending")
  end
end

Now, normally you would write one spec at a time, but I think I would bore my readers, so I combined these two. Also take note that I am using another custom RSpec matcher all_be_in_state(). It looks a lot like all_belong_to(), so I leave its implementation as an exercise to the reader (unless I can get another blog post out of it). To get these tests to pass I add a few lines of code:

  VALID_STATES.each do |_state|
    # Define _state as a state
    state _state
 
    # Add Comment.find__comments methods
    ( class &lt;&lt; self; self; end ).instance_eval do
      define_method "find_#{_state}_comments_by_user" do |_user|
        find_in_state( :all, _state, :conditions => ["user_id = ?", _user.id], :order => "created_at DESC" )
      end
    end
  end

I am not a method_missing kind of guy, and prefer the dynamic-method metaprogramming style. This lot of code defines class methods at runtime that find Comments in specific states. I am actually using whytheluckystiff’s metaid to hide some of the meta-junk, but I thought I should spell it out here for clarity.

Well, now we have a Comment class with two states and code to limit finds to cmments in a specific state. Right now, that is all I have. Here is the full code for the Comment class and the RSpec. You will see another custom RSpec matcher here, require_a().

class Comment < ActiveRecord::Base
 
  # The first element of this array is the initial state
  VALID_STATES = [ :pending, :approved ]
 
  acts_as_state_machine :initial => VALID_STATES[0]
 
  belongs_to :commentable, :polymorphic => true
  belongs_to :user
 
  event :approve do
    transitions :from => :pending, :to => :approved
  end
 
  validates_associated :user
  validates_presence_of :comment, :commentable_id, :commentable_type, :state,                           :user_id
 
  VALID_STATES.each do |_state|
    # Define _state as a state
    state _state
 
    # Add Comment.find_<state>_comments methods
    meta_def "find_#{_state}_comments_by_user" do |_user|
      find_in_state( :all, _state, :conditions => ["user_id = ?", _user.id],
                     :order => "created_at DESC" )
    end
  end
 
  class < < self
 
    # Helper class method to look up a commentable object
    # given the commentable class name and id
    def find_commentable(commentable_str, commentable_id)
      commentable_str.constantize.find(commentable_id)
    end
 
    # This could be refactored into find_<state>_comments_by_user (somehow)
    def find_comments_by_user(_user)
      find( :all, :conditions => ["user_id = ?", _user.id],
            :order => "created_at DESC" )
    end
 
    # Helper class method to look up all comments for
    # commentable class name and commentable id.
    def find_comments_for_commentable(commentable_str, commentable_id)
      find( :all,
            :conditions => [ "commentable_type = ? and commentable_id = ?",
                             commentable_str, commentable_id ],
            :order => "created_at DESC" )
    end
 
  end
 
end</state>
require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
 
module CommentSpecHelper
 
end
 
describe Comment do
 
  fixtures :comments
 
  include CommentSpecHelper
 
  before(:each) do
    @comment = Comment.new
  end
 
  it "should start out in pending state" do
    @comment.state.should == "pending"
  end
 
  it "sould transition to approved" do
    @comment = comments(:pending_comment)
    @comment.approve!
    @comment.state.should == "approved"
  end
 
  it "should require a comment" do
    @comment.should require_a(:comment)
  end
 
  it "should require a commentable_id" do
    @comment.should require_a(:commentable_id)
  end
 
  it "should require a commentable_type" do
    @comment.should require_a(:commentable_type)
  end
 
  it "should require a state" do
    @comment.should require_a(:state)
  end
 
  it "should require a user_id" do
    @comment.should require_a(:user_id)
  end
 
end
 
describe Comment, "class methods" do
 
  fixtures :comments, :recipes, :users
 
  it "should find all comments for a particular class" do
    # I happen to know that comment_one is a recipe comment
    Comment.find_commentable( "Recipe", comments(:comment_one).commentable_id ).should be_an_instance_of(Recipe)
  end
 
  it "should find comments by user" do
    Comment.find_comments_by_user( comments(:comment_one).user ).should all_belong_to( comments(:comment_one).user )
  end
 
  it "should find approved comments by user" do
    Comment.find_approved_comments_by_user( comments(:comment_one).user ).should all_be_in_state("approved")
  end
 
  it "should find pending comments by user" do
    Comment.find_pending_comments_by_user( comments(:comment_one).user ).should all_be_in_state("pending")
  end
 
  # This could be more specific
  it "should find comments for a particular class" do
    Comment.find_comments_for_commentable( comments(:comment_one).commentable_type, comments(:comment_one).commentable_id ).should be_an_instance_of(Array)
  end
 
end

–Dean

belong_to RSpec matcher

I was extending acts_as_commentable and needed a good RSpec test to check the returned objects from its finder methods belonged to the correct user. For example, Comment.find_comments_by_user( :some_user ) should all belong_to :some_user. I’ll be darned if that doesn’t look like a RSpec description. Since there is no all_belong_to matcher, I wrote one.

module ActiveRecordValidations
  class BelongTo
    def initialize(expected)
      @expected = expected
    end
 
    def matches?(args)
      args.all? do |target|
        @target = target
        @target.send(@expected.class.to_s.downcase) == @expected
      end
    end
 
    def failure_message
      "expected #{@target.inspect} to all belong to #{@expected}"
    end
 
    def negative_failure_message
      "expected #{@target.inspect} not to all belong to #{@expected}"
    end
  end
 
  def belong_to(expected)
    BelongTo.new( [expected] )
  end
 
  def all_belong_to(expected)
    BelongTo.new( expected )
  end
end

The matches? method takes an array of objects and goes through them with all? checking that they have a belongs_to the expected thing. Using the example above, each comment object returned by Comment.find_comments_by_user would get tested if comment.user== @user.

–Dean

First Brew-In


Weeks in advance the word went out through Craigslist, Facebook and TexAgs, trickling through emails from friend to friends. When brewday about 20 people showed to share beer, make beer, talk beer and have a good time. Three people brought their gear and we made 21 gallons of beer. I made an ordinary bitter, Ian made some hefeweizen, and a trio of brewers crafted chocolate raspberry stout.
I would say it was a great success. There was plenty of home and commercial brew going around and there was some great tri-tip off the bar-b-que. As is typical of many homebrew clubs, there was just a little bit of club business to discuss and a next meeting to decide on. Josh and Leslie volunteered their place for the next meeting and we quickly decided on May 3rd. I am pretty excited at the ease with which everyone got along and the eagerness of the group to continue gathering.

For 11 gallons of Ordinary Bitter:
Actual OG 1.034
Estimated IBU 26

Fermentables

  • 12 Lbs Crisp Maris Otter
  • 1.5 Lbs CaraMalt

Mash at 150° F with 1.7 quarts water per pound of grain for 90 minutes.

Hops

  • 1.0 oz 5.3% AA E.K. Goldings 90 minutes
  • 0.5 oz 9.0% AA Target (pellet) 90 minutes
  • 1.0 oz 5.3% AA E.K. Goldings 15 minutes
  • 1.0 oz 5.3% AA E.K. Goldings 1 minute

Starter of WYeast 1098, British Ale yeast.

My brew-day went smoothly until the end. My kettle screen let some hop leaves by and they got clogged somewhere leaving me with half-chilled wort. What I should have done was stop the chill, disassemble my apparatus and back-flush the system into the kettle. What I did instead was to dump the hot wort into the fermenter to air cool. I had to walk the fine line between pitching yeast into scalding wort and giving infection too much time to take hold. I think I pitched too hot because it took about 24 hours to see activity from a decent starter. I would really like to get my system hard-plumbed and on a stand.
I had two new gadgets to play with yesterday. The filter worked well once I realized it would be fine if I glued the casing together instead of worrying about replacing the filter after 10,000 gallons. I also bought a “Squirrel” brand paint mixer to aerate wort. That thing whipped up a six-inch head of foam in no time, making it a great purchase.

WTFAMH Kölsch

The temperature dropped into the low 30’s F for a few nights last week. On one of the last such nights I put the kölsch out overnight to crash cool in preparation for transfer to a keg. That crash, three weeks of sitting and a little Irish moss have done their job. I was rewarded with a clear yellow beer.
The kölsch turned out great. Pours clear and golden with a lingering thin white head. It has a medium-light body balanced to the malty side with enough bitterness to be barely noticeable. Since it was in the fermenter for so long the FG dropped to 1.009 and it tastes just a little over-attenuated. My only gripe with it is that I only got 3.5 gallons of it.

Where the Fuck Are My Hops Kölsch

First brew-day in Texas! There is no LHBS in B/CS so I ordered a Kölsch and a Bitter from Northern Brewer. I figured Kölsch is a good way to ease any megaswill-drinking new friends into good beer. Last night I went through boxes of packed equipment and retrieved what I need to brew. I had a nice starter ready. Everything looked set to go.

The recipe from NB:

Fermentables

  • 9 lbs Durst Pilsen
  • 1 lbs. Weyermann Pale Wheat

Hops

  • 1 oz. Argentina Cascade (60 min)
  • 1 oz. Argentina Cascade (30 min)

Wyeast #2565

I started the strike water around 11:30 (central time) just as a couple of my friends showed up to watch the process. When I went go get the ingredients from the cupboard I discovered that the hops were missing. Either I misplaced them or NB didn’t ship them…. This was the perfect opportunity to introduce the guys to the homebrewer’s creed: “Relax, don’t worry, have a homebrew.” Lacking homebrewed beer, I pulled out some Fancy Lawnmower ale from St Arnold’s Brewery (a kölsch) and went for the ingredients from the bitter. EKG, Target, Magnum…. This won’t quite make the BJCP standard definition of kölsch.

Hops

  • 0.75 oz 8% AA Target 60 mins
  • 1.00 oz 5% AA E.K. Goldings 30 mins

I also couldn’t find my depth meter (an aluminum ruler), so I had to eyeball the amount of strike water. It turns out I had too much, leaving me with a dilute mash and not enough sparge water. My efficiency is way off because in the end I collected about 4 gallons of 11% brix wort.

I am glad to be making beer again, glad to have six or eight new friends (enough to start a homebrew club) to share the process with (in no small part because of the beer for them). I’ll probably find those hops tomorrow.

Concise Signup & Signin Pages

Login, Signup

We are presented with these quick forms all the time. While it is easy to create standard login and signup pages, Amazon.com has a good one:

Amazon Sigin Image

What makes it good?

First of all, the prompts are written in plain English. Amazon sells to a wide slice of the population, meaning that about 15% of their customers are probably not very technology-saavy. (-2?) Anything they can do to ease the operation helps their customers buy.

Secondly, when a user visits Amazon.com, there is only one link: “Your account” instead of separate login and signup links. Simple is generally better.

Also note the standard “forgot your password” link plus an additional “has your email address changed?” question. Both are useful to have close at hand.

Implementation

Rails 2.0 strongly encourages you to design RESTful applications. Login forms are associated with Session objects, while signup forms go with User objects (rather, Brewer objects in our case). A simple redirect in the SessionsController#create method takes care of pointing a user in the right direction.

class SessionsController &lt; ApplicationController
  def create
    if params[:signin_action] == 'new_user'
      redirect_to new_brewer_path( :brewer =&gt; {:email =&gt; params[:email]} )
    else
      # Do sigin stuff
    end
  end
end

Note that we pass params[:email] to the new_brewer_path so that field is automatically populated on the next page. If you are using the generated scaffold, you will have to change your BrewersController#new method to instantiate a new @brewer object:

class BrewersController &lt; ApplicationController
  def new
    @brewer = Brewer.new(params[:brewer])
  end
end

Lastly, here is the extra test:

class SessionsControllerTest &lt; Test::Unit::TestCase
  def test_should_redirect_to_new_brewer_if_asked
    an_email = "dean@brewsession.com"
    post :create, :email =&gt; an_email, :signin_action =&gt; 'new_user'
    assert_redirected_to new_brewer_path(:brewer =&gt; {:email =&gt; an_email} )
    assert_nil session[:brewer_id]
  end
end

In a later post I will talk about how to implement the change password action in a RESTful way.

–Dean

Dean Moves

My wife got an offer to do her Forensic Entomology PhD at Texas A&M university. It is her dream job to teach and do Forensics work, and since I work from anywhere we packed up and moved to Bryan.

We arrived a week ago, signed a lease, dropped off the dogs and cats and headed to O’Bannon’s, a decent bar that we found during our October visit. It’s nice to be in a place where I can easily get Dogfish Head IPA, but this place does not have the beer diversity of the SF Bay Area. The change in cost of living is awesome though.

What does this mean for Brewsession?  Not a heck of a lot.  We have always been more of a virtual team that just happened to get together for beer a few times a month.  Further, since I have no friends here )-: I can devote more time to coding.  I will also do some friend-finding.  Danger: the municipal golf course is practically across the street.

Look for a resurgence of development work.

–Dean

Makin’ Glögg

Glögg is a Swedish drink that we make yearly. Only last year, however, did we get serious about storing the finished product. Because of the added sugar it begins a very sweet drink – too much for me, but after a month becomes drinkable. Two weeks ago I opened 2006’s batch. With age, it becomes smooth and spicy.

Last year I followed the recipe we have saved in the folds of The Joy of Cooking, but this year that book and recipe is packed away in preparation for our January move to Texas. Good thing Adie has an online copy.

I want to record the recipe I used this year so I can look back at it next year. I had to stray a little because the grocery store was out of a few things this morning (big surprise, Christmas Eve…)

In a saucepan mix:

  • A bottle of dry red wine. This year I used a $3 bottle of merlot.
  • Peel of a navel orange
  • 1/4 cup raisins
  • 1/4 cup prunes
  • 12 cinnamon sticks
  • 12 whole cloves
  • About a teaspoon of ground cardamom

Simmer for 15 minutes, then add

  • A bottle of ruby port
  • 1 c chopped almonds

Reduce heat to low, cover. In a pan heat over a medium flame

  • 1 cup sugar
  • 1/3 bottle Aquavit

Ignite the aquavit and burn until the sugar is dissolved. Add the remainder of the aquavit and cover to extinguish. Add this mixture to the mulled wine.

I left the glögg covered over low heat while I cleaned up, about 30 minutes. Strain out the mulling ingredients, bottle and label.

Skål!