Blank: A Starter App for r_c and shoulda Users


Oct 10, 2008

Bort was released recently. Peter Cooper speculated that "...it could well catch on as the de facto bare bones / generic Rails application". But, what about us non-RSpec users? There are dozens of us, I tell you. Dozens!

We build a lot of apps at GiraffeSoft — we love to experiment with whatever ideas excite us on any given day. We're all sick of editing restful_auth code, and moving tests over to Shoulda and the one assertion per test pattern. Bort doesn't suit our needs. So, blank was born.

Right now, it's pretty simple. It has authentication, and forgot password. That's about it. But, it's no biggie. Since blank creates your new app as a git repo that shares history with blank's repo, you can pull in changes we make at any time. So, when we finally get around to implementing openid support, you'll get it for free, if you start with blank.

Vendored

All of our standard tools (and rails) are vendored:

  • active_presenter
  • andand
  • attribute_fu
  • hoptoad
  • mocha
  • rake
  • restful_authentication
  • ruby-openid
  • will_paginate

Installation

Installing blank is as easy as running a rake task. Except that blank uses thor instead, because it’s the new hotness, and it supports remote tasks.

Just install thor:

$ sudo gem install thor

…then install blank’s thor tasks:

$ thor install http://github.com/giraffesoft/blank/tree/master%2Fthorfiles%2Fblank.thor?raw=true

…then you’re ready to create a new app with blank:

$ thor blank:new_app the_name_of_my_app the@git.repo.it.will.live.in

That’s it! The thorfile will display a couple of rake notes where you should replace blank app with your app's name. Also, you'll want to fill in your hoptoad API key in config/initializers/hoptoad.rb.

If we improve the thor file, all you have to do is run:

$ thor update blank

before creating your next app, and you’ll get the changes automagically.

Development

All development will be done at the github repo. Fork away :)

Credits

Blank was created by me, with contributions from Daniel Haran.


Introducing ActivePresenter: The presenter library you already know.


Jul 27, 2008

Presenters were a hot topic in the rails community last year. A lot of prominent bloggers wrote about using them, and the implementations they had come up with. Oddly, though, when I needed one a couple of weeks ago, I was unable to find a suitable implementation. Lots of articles — no code.

Let's answer the question on everybody's mind before we move on. Feel free to skip ahead if you already know the answer.

WTF is a presenter?!

In its simplest form, a presenter is an object that wraps up several other objects to display, and manipulate them on the front end. For example, if you have a form that needs to manipulate several models, you'd probably want to wrap them in a presenter.

Indeed, attribute_fu solves this problem for some cases. However, when you're dealing with unrelated models, or, really, any situation other than a parent saving its children, you're probably better off using a presenter.

Presenters take the multi model saving code out of your controller, and put it in to a nice object. Because presenter logic is encapsulated, it's reusable, and easy to test.

Want one?

ActivePresenter

Daniel and I wrote most of this on the train ride over to RubyFringe. It is an ultra-simple presenter base class that is designed to wrap ActiveRecord models (and, potentially, others that act like them).

ActivePresenter works just like an ActiveRecord model, except that it works with multiple models at the same time. Let me show you.

Imagine we've got a signup form that needs to create a new User, and a new Account. We'd create a presenter that looks like this.

class SignupPresenter < ActivePresenter::Base
  presents :user, :account
end

Then, we'd write a new action like this one:

def new
  @signup_presenter = SignupPresenter.new
end

And a form:

<%= error_messages_for :signup_presenter %>

<%- form_for @signup_presenter, :url => signup_url do |f| -%>
  <%= f.label :account_subdomain, "Subdomain" %>
  <%= f.text_field :account_subdomain %>
  <%= f.label :user_login, "Login" %>
  <%= f.text_field :user_login %>
<%- end -%>

A create action:

def create
  @signup_presenter = SignupPresenter.new(params[:signup_presenter])
  
  if @signup_presenter.save
    redirect_to dashboard_url
  else
    render :action => "new"
  end
end

Lastly, an update action:

def update
  @signup_presenter = SignupPresenter.new(:user => current_user, :account => current_account)
  
  if @signup_presenter.update_attributes(params[:signup_presenter])
    redirect_to dashboard_url
  else
    render :action => "edit"
  end
end

Seem familiar?

If you're using r_c, most of this comes for free with:

class SignupsController < ResourceController::Base
  model_name :signup_presenter
end

For more on complex forms in rails, and the presenter pattern, see my upcoming PeepCode screencast!

Organization

I have been sticking my presenters in app/presenters. If you want to do the same, you'll need to add a line like this to your environment.rb:

config.load_paths += %W( #{RAILS_ROOT}/app/presenters )

Get It!

As a gem:

$ sudo gem install active_presenter

As a rails gem dependency:

config.gem 'active_presenter'
Or get the source from github:
$ git clone git://github.com/giraffesoft/active_presenter.git

(or fork it at http://github.com/giraffesoft/active_presenter)

Also, check out the RDoc.