Showing posts for tag: ruby

Rendering partials in toto

April 19th 2012

toto is a fantastic lightweight blogging engine. In fact, at the time of writing, this very blog is running on it. By looking at dorothy you can see how it uses a layout and templates to render content. However, by default, it does not provide support for template partials.

However, that’s easily solved with a little monkey patching:

module Toto
  class Site
    class Context
      def to_partial(page)
        to_html page, @config
      end
    end
  end
end

Now you can include partials in your templates like this:

<%= render 'sidebar', :partial %>

Now, I’m not a fan of monkey patching for a number reasons, not least of which is the fact that a good monkey patch is often a missed opportunity to improve an open source project. With that in mind, here is the pull request to have this functionality added to toto itself.

tags: toto, ruby

Duplicate Active Model validation errors

April 12th 2012

When attempting to test a model using Active Model validations, I came across a rather odd problem.

require 'active_model'

class Person
  include ActiveModel::Validations
  validates_length_of :name, :maximum => 40, :message => 'name too long'
  attr_reader :name
  def initialize(attrs)
    @name = attrs[:name]
  end
end

I was seeing duplicate 'name too long' error messages in the errors hash.

describe Person do
  describe 'validation' do
    it 'should be invalid if name is too long' do
      person = Person.new(:name => 'a' * 41)
      person.should_not be_valid
      person.errors[:name].should == ['name too long']
    end
  end
end

The above spec failed with the following message:

Failures:

  1) Person validation should be invalid if name is too long
     Failure/Error: person.errors[:name].should == ['name too long']
       expected: ["name too long"]
            got: ["name too long", "name too long"] (using ==)
     # ./spec/person_spec.rb:17

Some further digging revealed that the Person was being loaded twice by the require method. require was being called twice with two different paths, which both resolved to the file containing Person. Removing the extra call to require fixed the issue. This seems to be a problem particular to ruby 1.8.7.

The runnable code examples reproducing this issue can be found here.

Introducing mailcrate

March 12th 2012

Often when I’m working near the top of the test automation pyramid, I find myself needing to test interactions with outside services such as SMTP servers.

On projects in the past, I’ve been able to leverage java tools such as greenmail, which lets me have logic like this.

public class MailerTest {

  private Greenmail greenmail

  @Before
  public void startGreenmail() {
    greenMail = new GreenMail();
    greenMail.start();
  }

  @After
  public void stopGreenmail() {
    greenMail.stop();
  }

  @Test
  public void testYourSendingCode() throws Exception {    
    new Mailer().send("to@localhost.com", "body");

    assertEquals("body", GreenMailUtil.getBody(greenMail.getReceivedMessages()[0]));
  }

}

This library is particularly useful as it allows interrogation of sent mails directly from the test. However, I have had trouble finding an equivalent gem for ruby development. However, there is the fantastic command line tool, mailtrap. Mailtrap is written in ruby and:

Mailtrap waits on your chosen port for a client to connect and talks just enough SMTP protocol for ActionMailer to successfully deliver its message.

Unfortunately, mailtrap does not play nicely with automated tests. It writes out captured emails to the filesystem, and there is no easy way to start, stop or interrogate a server in memory. However, mailtrap and greenmail have acted as the inspiration for mailcrate. Mailcrate is designed to be run from your test code and allows interrogation of sent mails from the test itself. For example:

require 'mailcrate'

describe Mailer do

  before do
    @mailcrate = Mailcrate.new(2525)
    @mailcrate.start
  end

  after do
    @mailcrate.stop
  end

  it 'should use Mailcrate to send mails' do
    mail = Mailer.welcome_email('a@b.com')
    mail.deliver

    @mailcrate.mails[0][:from].should == 'from@example.com'
    @mailcrate.mails[0][:to_list].should include 'a@b.com'
    @mailcrate.mails[0][:body].should include 'Full of awesomeness.'
  end

end

Mailcrate has been published as a gem and can be used by running:

gem install mailcrate

Mailcrate is still rather immature. Any feedback would be welcomed, both here on this blog or its github page.

tags: ruby, mailcrate

subscribe subscribe to this tag

Welcome. Here you'll find Adam Scott's blog and photos. Adam is an agile software developer by trade and a photographer by night.

stuff

related tags