Text

Padrino Rake tasks with Whenever

Padrino as a framework is an interesting middle ground between Rails and Sinatra. However, it breaks from the norm in that it doesn’t have a traditional Rakefile, opting instead to pass everything through its padrino command (e.g., padrino rake console). Ordinarily this isn’t a problem, but it slightly conflicts with the excellent whenever gem for managing crontabs on a production server, since whenever’s default rake job type assumes there’s a traditional Rakefile.

Luckily whenever offers a simple solution by defining a custom job_type:

config/schedule.rb

job_type :padrino_rake, 'cd :path && padrino rake :task -e :environment'

every :hour do
  padrino_rake 'crawl'
end

Run after a deploy, my crontab will now look like this:

@hourly /bin/bash -l -c 'cd /path/to/my/project && padrino rake crawl -e production'
Text

Complex MetaSearch forms with Formtastic

meta_search lets you perform advanced queries on your ActiveRecord models, and Formtastic helps in building semantic forms quickly and easily.

Today I had need to build an advanced search form that would let the user define a search where an attribute was between two values. For example, finding users whose age is between 20 and 30.

MetaSearch defines the multiparameter_field form helper method, but getting that helper to work with Formtastic required some doing:

First, define the :between where as described in the README:

config/initializers/meta_search.rb

MetaSearch::Where.add :between, :btw,
  :predicate => :in,
  :types => [:integer, :float, :decimal, :date, :datetime, :timestamp, :time],
  :formatter => Proc.new {|param| Range.new(param.first, param.last)},
  :validator => Proc.new {|param|
  param.is_a?(Array) && !(param[0].blank? || param[1].blank?)
}

Next, we need to define a custom form builder class and then tell Formtastic to use it:

config/initializers/multi_param_form_builder.rb

class MultiParamFormBuilder < Formtastic::SemanticFormBuilder
  # Allows <tt>:as => :between</tt> which utilizes MetaSearch's
  # <tt>multiparameter_field</tt> helper
  def between_input(method, options = {})
    input_options = options.delete(:input_html) || {}
    label_options = options_for_label(options)
    label_options[:for] ||= input_options[:id]

    label(method, label_options) <<
      multiparameter_field(method, {:field_type => :text_field},{:field_type => :text_field}, input_options)
  end
end

config/initializers/formtastic.rb

Formtastic::SemanticFormHelper.builder = MultiParamFormBuilder

Now in a view, use Formtastic and MetaSearch as normal, just tell Formtastic to render the field as :between:

app/views/users/_search.html.haml

= semantic_form_for @search, :method => :post do |form|
  = form.inputs do
    = form.input :age_between, :as => :between
  = form.buttons do
    %button.button{:type => 'submit'} Search

And that’s it!

Text

Alphabetizing a block of text in Vim

Today I had need to alphabetize a block of code in Vim, but on each line there was text which I didn’t want to be part of the sort. An example describes it best:

item 65110 #Heart of Ignacious
item 65111 #Scepter of Ice
item 65113 #Hydrolance Gloves
item 65114 #Feludius' Mantle
item 65115 #Glaciated Helm
item 65116 #Treads of Liquid Ice
item 65117 #Glittering Epidermis
item 65118 #Crushing Weight
item 65119 #Gravitational Pull
item 65120 #Arion's Crown
item 65121 #Terrastra's Legguards
item 65122 #Dispersing Belt

Currently the lines are sorted numerically. I needed the lines to be sorted alphabetically based on the content of the comments (the stuff after the #). Vim made this stupid-easy:

  1. Highlight the lines using visual line mode (V)
  2. Run :sort /.*#/

That’s it. The argument to sort tells it to use everything after the pattern. Beautiful.

Tags: vim
Text

An RSpec2 / Shoulda Controller Gotcha

I’m in the process of upgrading a Rails 2.3.8 app to Rails 3, and part of that process involved upgrading to RSpec2. I made use of Shoulda, mostly in my controller tests, and I ran into a frustrating issue that hopefully I can prevent for other people with this post.

A simple example controller spec looked like this:

  require 'spec_helper'

  describe AchievementsController, "GET index" do
    before { get :index }

    it { should respond_with(:success) }
    it { should assign_to(:achievements).with_kind_of(Array) }
    it { should assign_to(:members).with_kind_of(Array) }
    it { should render_template(:index) }
  end

Running this spec with RSpec2 generated this error:

  Failures:
    1) AchievementsController GET index 
       Failure/Error: it { should respond_with(:success) }
       undefined method `response_code' for nil:NilClass
       # gems/activesupport-3.0.0/lib/active_support/whiny_nil.rb:48:in `method_missing'
       # (path)shoulda/lib/shoulda/action_controller/matchers/respond_with_matcher.rb:57:in `response_code'
       # (path)shoulda/lib/shoulda/action_controller/matchers/respond_with_matcher.rb:48:in `correct_status_code?'
       # (path)shoulda/lib/shoulda/action_controller/matchers/respond_with_matcher.rb:30:in `matches?'
       # ./spec/controllers/achievements_controller_spec.rb:12
       # gems/activesupport-3.0.0/lib/active_support/dependencies.rb:239:in `inject'

    2) AchievementsController GET index 
       Failure/Error: it { should assign_to(:achievements).with_kind_of(Array) }
       Expected action to assign a value for @achievements
       # ./spec/controllers/achievements_controller_spec.rb:13
       # gems/ree-1.8.7-2010.02@rails3/gems/activesupport-3.0.0/lib/active_support/dependencies.rb:239:in `inject'

    3) AchievementsController GET index 
       Failure/Error: it { should assign_to(:members).with_kind_of(Array) }
       Expected action to assign a value for @members
       # ./spec/controllers/achievements_controller_spec.rb:14
       # gems/ree-1.8.7-2010.02@rails3/gems/activesupport-3.0.0/lib/active_support/dependencies.rb:239:in `inject'

The solution is ridiculously simple:

  require 'spec_helper'

  describe AchievementsController, "GET index" do
    before { get :index }
    subject { controller } # <- ADD THIS

    it { should respond_with(:success) }
    it { should assign_to(:achievements).with_kind_of(Array) }
    it { should assign_to(:members).with_kind_of(Array) }
    it { should render_template(:index) }
  end

It makes perfect sense in retrospect, but it’s a little frustrating that in order to find this solution, I had to look through Shoulda’s commit log for a mention of rspec2, which noted a change to its Cucumber features, which included this subject line.