Welcome to Giant Robots Smashing Into Other Giant Robots — a weblog about development, business, design and technology — written by thoughtbot.

Widgetfinger Is Go.

A long time ago, I posted here, about our upcoming product, Widgetfinger. To refresh your memory, Widgetfinger is Simple Content Management for Simple Websites. Its a content management and hosting service specifically built for design firms that includes normal hosting as well as email, and statistics and a few other things that we think are pretty helpful. If you’re a small design firm that builds what we call Brochure websites (Home, About, Services, Contact, and not much else) then widgetfinger is built for you – and you can signup and start using it for free today.

At the time, it seemed like the release of Widgetfinger was imminent – we had successfully started hosting quite a few websites in it, we successfully moved our own website and email hosting to Widgetfinger, and everything was going well. Well, this has certainly been a lesson for us that client work can easily derail the best intentions of our own product development.

All that said, we’ve been incrementally improving things since that time, expanding its use to more websites, and the time has come to really get this show on the road.

So, I’m happy to officially launch Widgetfinger – the website for Widgetfinger is online, and you can signup and start using it today!

I’ll keep this post short, and plan on posting some more info on Widgetfinger in the near future. Suffice to say, we look forward to hearing your feedback as you start to use it – we will continue to improve it based on your feedback. And if you’re just a “normal rails developer” and are thinking Widgetfinger doesn’t apply to you – you’re probably right – but we’ll definitely be posting here about some of the tech used in it, or the things we’ve learned along the way.

Posted by Chad Pytel on May 9th | 8 comments | Filed Under: Business Development Technology

Skinny Controllers, Skinny Models

I hear a lot of people recommending the “skinny controller, fat model” approach to Rails development. I’m all for keeping controllers simple, but who wants a fat model? If your editor slows down while loading up your model files, I have some advice: put your models on a diet.

Let’s say you have an application that needs to handle PDF documents. You have a very simple Document model to keep track of them:

1
2
3
4
5
class Document < ActiveRecord::Base
  validates_presence_of :title
  has_attached_file :pdf
  validates_attachment_presence :pdf
end

It’s just you and a skinny, attractive model. It’s going to be a good day.

But after your application has been live for a few days, it becomes clear that you need to provide a way to view these documents online, and your client’s weapon of choice is HTML. So, you add a method to convert your PDFs to HTML documents:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Document < ActiveRecord::Base

  # ...

  def convert_to_html
    # ...some fancy magic...
  end

  def converted_to_html?
    File.exist?(html_file_path)
  end

  def html_file_path
    File.join(HTML_STORAGE_DIR, pdf.original_filename + '.html')
  end

  # probably a few more methods...

end

Everything is working great, but now you have to look through all this HTML junk whenever you’re working on Document. Worse, the tests for HTML conversion and documents are all mixed up. Even worse, Document is getting pretty fat, and its model friends won’t stop making fun of it. If you don’t do something soon, this could mark the end of your good days with skinny models. A very common and simple technique can save us from this message: composition.

For some reason, many Rails developers seem to avoid using model classes that are not stored in the database. This leads to shoving too much key functionality into one of your key models, which of course leads to fat, incomprehensible model files and tests. I see no reason for an HTML file to have its own, separate entry in the database, but it certainly has enough behavior to warrant its own class. Let’s pull that functionality into an HtmlFile class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class HtmlFile

  attr_reader :source_path

  def initialize (source_path)
    @source_path = source_path
  end

  def name
    @name ||= File.basename(source_path) + '.html'
  end

  def generate
    # ...some magic with file.path here...
    self
  end

  def path
    @path ||= File.join(HTML_STORAGE_DIR, name)
  end

  def exists?
    File.exist?(path)
  end

  # ... some other useful methods ...

end

Now we have another beautiful model. Let’s get these two acquainted:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Document

  # ...

  def html_file
    @html_file ||= HtmlFile.new(pdf.original_filename)
  end

  def convert_to_html
    @html_file = HtmlFile.new(pdf.original_filename).generate
  end

end

Result: two beautiful, skinny models. Analysis: it’s going to be a very good day.

Posted by Joe Ferris on May 1st | 13 comments | Filed Under: Development

Pitfalls in RESTful "wizards"

In an application we’re currently building, users go through a wizard to order teams. We implemented this as RESTful controllers – teams, purchases, and orders.

The relevant wizard steps are:

  1. teams/new
  2. teams/:id/purchases/new
  3. orders/new

When each step is submitted, the related create action is called and the user is redirected to the next new action.

Pitfall: the user hits the back button.

On step 3, the user hits the back button. If they re-submit step 2, they will get a validation error because they cannot create two purchases for a team.

There’s a temptation here to stray from RESTful design. Don’t!

When the user hits the back button from step 3, we want to send them to purchases/edit for their newly-created object instead of purchases/new.

Solution: Force the browser to not cache

To ensure that the page isn’t cached by the browser and will always be re-fetched, we add a before_filter to the purchases controller which calls a private method on ApplicationController:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
before_filter :no_cache, :only => [:new]

private

  def no_cache
    response.headers["Last-Modified"] = Time.now.httpdate
    response.headers["Expires"] = 0
    
    # HTTP 1.0
    response.headers["Pragma"] = "no-cache"
    
    # HTTP 1.1 'pre-check=0, post-check=0' (IE specific)
    response.headers["Cache-Control"] = 'no-store, no-cache, must-revalidate, max-age=0, pre-check=0, post-check=0'
  end

Next, if the team already has a purchase, we redirect to the edit action using another before filter on the purchases controller:

1
before_filter :redirect_to_edit, :only => [:new], :if => :team_has_registration_purchase?

#team_has_registration_purchase? is a method on the purchases controller. If the :if syntax is unfamiliar to you, its provided to us by our plugin, when.

Pitfall: ‘not caching’ only works in Firefox.

To the best of our knowledge, setting the HTTP headers should have worked in all browsers, but it did not work in Safari or in IE 6 and 7. A little more research proved that any page with an iframe on it will never be cached, and will always be refetched.

Solution: iframe

So, we add this to views/purchases/new:

<iframe style="height:0px;width:0px;visibility:hidden" src="about:blank"> this frame prevents back forward cache </iframe>

This works. We now have cross-browser no-caching in a RESTful wizard.

The iframe hack feels a little dirty, though. Does anyone know a better way? Or, do we live with it, similar to using a hidden frame for “Ajax” file uploads with responds_to_parent ?

This concept might be useful outside of these more complex, wizard type controller actions, and might come in handy if you had just a normal restful controller where you wanted the user to get the edit action instead of the new action if they use the back button. Have you done something like this before, or can you think of a different way to accomplish that?

photo courtesy of Michael Porter via Flickr

Posted by Chad Pytel on April 25th | 12 comments | Filed Under: Development

not yet

Ok here’s an app as of right now.

All the app consists of are some forms for creating users, some forms for users to create comments, plus 1 additional page that displays each user and the total # of comments they have created. There is NO page that displays a comment and its user who created it.

The correct domain model based on the requirements right now is:

1
2
3
4
5
6
7
8
class User < ActiveRecord::Base

  has_many :comments

end

class Comment < ActiveRecord::Base
end

This association is unidirectional, it can only be traversed in one direction. There is no point in making this association bidirectional by adding a corresponding belongs_to :user in Comment. Adding that would be premature and a case of massive over-engineering. Since the association from Comment to User currently is not used in the app, adding it would just cause unnecessary complexity.

There is nothing wrong with unidirectional associations. Don’t make all associations bidirectional when its just not necessary; someday it might be but until then don’t do it.

Posted by Jared Carroll on April 24th | 16 comments | Filed Under: Design Development Technology

mas o menos

Everyone seems to trip up when it comes to #< and #> and dates and times.

1
2
3
4
5
6
7
8
9
10
11
  def recent
    if published_on > 1.week.ago
      # blah
    end
  end

  def old
    if published_on < 1.week.ago
      # blah
    end
  end

Nobody thinks of dates and times as numbers, so its hard to do comparisons on them quickly like you would with numbers. So lets add 2 methods to our dates and times.

1
2
3
4
5
6
7
  def after?(other)
    self > other
  end

  def before?(other)
    self < other
  end
1
2
3
4
5
6
7
8
9
10
11
  def recent
    if published_on.after?(1.week.ago)
      # blah
    end
  end

  def old
    if published_on.before?(1.week.ago)
      # blah
    end
  end

Luckily our “good friends” over at dzone have already a “real solid” impl of these 2 queries. LEFT_SIDE_LATER!

..in other news…

Posted by Jared Carroll on April 17th | 4 comments | Filed Under: Design Development Technology

thoughtbot is hiring

We are hiring web developers and web designers in both Boston and New York, NY.

What are we up to?

We built Shoulda, an eclectic set of additions to Test::Unit; Paperclip to manage uploaded files without hassle; Jester, a REST/ActiveResource client library written in Javascript, and Squirrel, an enhancement for ActiveRecord's find syntax; — amongst some other projects.

Chad (President) and Jon (CTO) co-authored a technical book titled Pro Active Record: Databases with Ruby and Rails, which explores the ins and outs of the ActiveRecord ruby library. You can buy it today at Amazon.com.

About thoughtbot, inc.

We are a small web application development consulting business, with offices in Boston, MA and New York, NY. If you're looking to find a team for your next web development project or your new web application — get in touch.