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.


attribute_fu and jQuery shake hands


Apr 03, 2008

This blog has been quiet of late, because I'm working on a couple of exciting, but still top-secret projects. Anyway, I recently moved one of those projects over to jQuery, because of its speed, syntax, and general awesomeness. Tonight, when I went to create a multi-model form with attribute_fu, I was stopped dead in my tracks by its heavy dependency on prototype. A few minutes of hacking later, a_f and jQuery are playing rather nicely together.

Get it from the jquery branch of a_f's git repo. If you aren't using git yet, this might be just the excuse you need to check it out! Or, download a tarball from github. After you install the plugin, you'll have to copy its one javascript dependency (jQuery templates) from the javascripts directory over in to your public/javascripts and require it in your layout.


Look out Ryan Bates - There's a New Screencast in Town


Jan 27, 2008

So, I'm sitting there on Friday evening working on a screencast introduction to attribute_fu, when Fabio Akita sends me an email to tell me he just created one for resource_controller! It was like he'd read my mind.

Fabio was nice enough to agree to let me put some title screens on his r_c screencast, but I couldn't seem to get it to export while still looking decent. So, here's the first episode of GiraffeCasts (for those of you who don't know, my company is called GiraffeSoft), and Fabio's awesome resource_controller introduction.

Episode 1: attribute_fu

Episode one is a quick walk through the basics of attribute_fu. Get it here.

As promised, here is the code from the screencast:

## _task.html.erb
<p class="task">
  <b>Title:</b><br/>
  <%= f.text_field :title %>
  <%= f.remove_link('Remove') %>
</p>
## _form.html.erb
<div id="tasks">
  <%= f.render_associated_form(@project.tasks, :new => 3) %>
</div>
<%= f.add_associated_link('Add Task', @project.tasks.build) %>
class Project < ActiveRecord::Base
  has_many :tasks, :attributes => true
  
  private
    before_save :remove_blank_tasks
    def remove_blank_tasks
      tasks.delete tasks.select { |task| task.title.blank? }
    end
end

To get attribute_fu:

$ piston import http://svn.jamesgolick.com/attribute_fu/tags/stable vendor/plugins/attribute_fu

Fabio's resource_controller Screencast

Fabio Akita gives an excellent tour of resource_controller, in screencast form. Get it here.

See Ya Next Time

That's all for today. Check back for more GiraffeCasts!


Introducing AttributeFu: Multi-Model Forms Made Easy


Dec 01, 2007

Ever needed to create a form that works with two models? If you have, you know that it's a major pain. It really seems like it should be easier, doesn't it? Powerful, SQL-free associations join our models; helpers build our forms in fewer keystrokes than it takes to call somebody a fanboy in a digg comment. But, as soon as you want to put the pieces together — as soon as you seek multi-model form bliss, the whole system falls apart.

Ryan Bates has popularized a few recipes for cooking up just such a dish (we all owe that man a debt of gratitude, don't we?). Great solutions (thanks Ryan!). There are only two flaws to speak of.

  • AJAX-friendliness: What is this - web1? Maybe we should all build our sites in frames, and pepper them with blinking text.
  • It's not a plugin: You mean I have to write code!? I thought rails was going to wash my dishes, walk my dog, and build my websites, while I sat outside on the porch smoking cigars, praying to DHH.

Being the compulsive pluginizer that I am, I simply couldn't resist this great opportunity.

attribute_fu

attribute_fu makes multi-model forms so easy you'll be telling all of your friends about it. Unless your friends are serious geeks, though, most of them will probably hang up on you. So, I recommend resisting that urge, unless you're looking for a good bedtime story.

To get started, enable attributes on your association (only has_many for now).

class Project < ActiveRecord::Base
  has_many :tasks, :attributes => true
end

Your model will then respond to task_attributes, which accepts a hash; the format of the which is a little bit different from what Ryan describes in his tutorials. Here's an example.

@project.task_attributes => { task_one.id => {:title => "Wash the dishes"},
                              task_two.id => {:title => "Go grocery shopping"},
                              :new => {
                                "0" => {:title => "Write a blog post about AttributeFu"}
                              }}

Follow the rules, though, and attribute_fu will shield you from the ugly details.

Form Helpers

The plugin comes with a set of conventions (IM IN UR PROJECT, NAMIN UR PARTIALZ). Follow them, and building associated forms is as easy as it should be. Take note of the partial's name, and the conspicuously absent fields_for call.

## _task.html.erb
<p class="task">
  <label for="task_title">Title:</label><br/>
  <%= f.text_field :title %>
</p>

Rendering one or more of the above forms is just one call away.

## _form.html.erb
<div id="tasks">
  <%= f.render_associated_form(@project.tasks) %>
</div>

You may want to add a few blank tasks to the bottom of your form — formerly requiring an extra line in your controller.

<%= f.render_associated_form(@project.tasks, :new => 3) %>

This being web2.0, removing elements from the form with Javascript (but your boss calls it AJAX) is a must.

## _task.html.erb
<p class="task">
  <label>Task</label><br/>
  <%= f.text_field :title %>
  <%= f.remove_link "remove" %>
</p>

Adding elements to the form via Javascript doesn't require any heavy lifting either.

## _form.html.erb
<%= f.add_associated_link('Add Task', @project.tasks.build) %>

It's that easy.

Last but not least (okay, maybe least), if you're one of those people who just has to be different - who absolutely refuses to follow the rules, you can still use attribute_fu (I guess...). See the RDoc for how.

Plugins, Plugins, Get Your Plugins

$ piston import http://svn.jamesgolick.com/attribute_fu/tags/stable vendor/plugins/attribute_fu

Check out the RDoc for more details.

Come join the discussion on the mailing list.