A delicious blend of Ruby and Rails…

Overlap of Confidence with Static Typing

February 7th, 2008 benhughes

Since working with Ruby and other dynamic languages, I’ve thought a lot about the differences between statically-typed and dynamically-typed languages and what makes them different. Statically-typed languages guarantee some level of confidence of workability — but this comes at a huge cost of flexibility, and more importantly overlaps with software testing, not making efficient use of the concept of testing.

Software testing can be used to make up for some of the lost confidence resulting from dynamic typing, yet since they must be done regardless, the outcome is suboptimal with static languages - there is an overlap between the confidence generated from static typing and the confidence generated from the test suite. With dynamic languages there is much less overlap: the test suite makes up for the confidence lost from dynamic typing, yet is also there to ensure the software works as expected.

Wrapping Conditional Access with with_scope

February 2nd, 2008 benhughes

ActiveRecord::Base exposes a great way of keeping access control DRY. A very common paradigm in web application development is showing “all” of something to administrators but only only “active” of something to regular users/visitors. In non-ORM PHP you might do something like like this in each SQL statement:

$sql  = "SELECT * FROM entries WHERE type = 1 ";
$sql .= (!$is_admin ? "AND active = 1" : "");

This isn’t a very well-architected approach since this type of tacking onto the SQL string would have to be done in any statement that involved this table, for all of your “actions” like show, edit, and index. It tightly couples this particularly piece of add-on logic to your base code. In Rails we can scope out this functionality to a “scope_access” method in our controller like so:

class EntriesController < ApplicationController
  around_filter :scope_access

  # (Action Methods)

  protected

  def scope_access
    unless current_user && current_user.is_admin?
      Entry.send(:with_scope, :find => {:conditions => 'active = 1'}) do
        yield
      end
    else
      yield
    end
  end
end

We are declaring an around_filter which uses with_scope if the current user is an admin, otherwise it will do so without scope. This is an excellent example of how Rails allows you to architect your code to be very elegant. Note that with_method is now a protected method on ActiveRecord::Base hence our need to use ClassName.send.

The with_scope method is actually useful for many other purposes including running many but similar find statements. Aside from finders, this can actually scope attributes on create and more. I’d highly recommend you check it out in the Rails documentation and start making extensive use of it.

What it takes to appreciate Ruby

February 2nd, 2008 benhughes

Antagonistic attitudes towards Ruby and in particular Ruby on Rails abound. Many web developers feel uneasy about the rise of a strange new framework that is attracting disciples daily. I’ve casually chatted with a few people who have negative attitudes about Ruby and the most striking aspect about everyone I’ve spoken with is that after prodding a bit at their understanding and experience level with Ruby I find they only have a surface-level understanding of Rails and no experience whatsoever. I have not once found someone who was well-versed in both Ruby on Rails (as in.. has actually built an application using it) and in any of the other number of web technologies out there, who was not at the very least appreciative about Rails and optimistic about its future.

What I’m trying to get at here is that to appreciate Ruby you have to know Ruby, and know it well. A surface-level examination of Rails by myself over one year ago left me in the same ignorant state that many Ruby antagonists are at right now, complaining about Ruby’s ability to scale and the restrictive nature the Rails framework involves. Even reading a few chapters out of the Agile book might leave one with this characterization. Yet the more I began to understand Rails and even more importantly the dynamic Ruby programming language, the more positive my attitudes towards Rails were.

It’s interesting that I find this particular understanding imbalance even more widespread and frustrating in economics: to appreciate the free market, you have to understand the free market. So few people truly understand economics and as a result their arguments are ripe with economic fallacies and mischaracterizations of fact. Economists on average believe that the free market works significantly better than non-economists. This isn’t a conspiracy: it’s because they actually understand economics.

There will always be people in any field that attack something they don’t understand for whatever reason. Those making arguments against Rails at least owe it to their opponents to actually understand what they are talking about. I find such is rarely the case.

New SliceHost VPS

February 2nd, 2008 benhughes

Until now I’ve been running a my personal sites and a few other random sites I host on a dedicated box running CentOS 4 and Plesk.  Last week I took the plunge for a SliceHost VPS and decided to configure everything myself and try to squeeze it all on a 256MB slice for $20/month.  Although there isn’t anything specifically about SliceHost that makes it well-suited for Rails hosting (after all, it’s just a Linux VPS - put whatever you want on it), the SliceHost guys are Rails developers and the documentation available on articles.slicehost.com is geared towards Rails production environments.

I wanted to use the switch as a learning experience with setting up a cluster of mongrels behind Apache 2.2, a setup I’ve never tried before.  I’ve used FastCGI with Apache and Nginx proxying to mongrel clusters, but I was looking for a more powerful setup using Apache as the front-end web server.  So I configured Apache 2.2 (with the Debian layout, much different than the “conventional” layout) with mod_proxy_balancer and PHP.  MySQL and Apache were fine-tuned to run with the smallest memory footprint that is practical.  Apache is proxying to a cluster of mongrels hosting BenHughes.name (which will eventually be a larger site) and a new Facebook application I’m currently developing.  

To reduce the memory requirement, and because I find it a better piece of software, I switched this blog and my economics blog to WordPress running as PHP within Apache.  I toyed with the idea of keeping these on Typo and Mephisto, respectively, and running them with just one mongrel instance, but doing so would really eat up my memory on my 256MB slice quickly.  WordPress is pretty nice and has a much larger community of people developing themes.

I also moved my two Subversion repositories over (one private, one public and yet to be used: http://svn.railsgarden.com/).  Previously I was hosting DNS and E-mail which was just a hassle, so I decided to switch all of my domains to Google Apps and host the DNS at SliceHost, maintainable through their management portal. 

I have to say I’ve been exceedingly happy with SliceHost thusfar - their management portal is simple and to-the-point with no BS.  They have dedicated resources and do not oversell.  $20/month for what I’m getting is a pretty darn good deal - it feels good to continue having root on my own Linux system out there in a data center.  Hell for $20/month a VPS is a great way to just fool around with and learn with.  I may get another slice just for that purpose.

Book Review: Advanced Rails Recipes

January 6th, 2008 benhughes

I’ve owned the original “Rails Recipes” book by Chad Fowler for a while now and it’s packed full of interesting information, but little of it I would consider “advanced”. When I heard a new book by The Pragmatic Programmers called “Advanced Rails Recipes”, meant to be similar in form to the previous book but explaining more advanced techniques, I was very interested. Unfortunately it seems the publish date of this book has been pushed back a few times and it is now mid-March. Luckily it is available in beta PDF form online so last night I took the plunge and decided to buy it. It’s quick to read through and several of the recipes I skipped over because I wasn’t particularly interested, but suffice it to say that there is a lot of good stuff in this book. Some of the content isn’t very original, but some recipes really exceeded my expectations in originality and usefulness.

I won’t give an outline of the book since that’s available online, but let me point out a few very interesting recipes:

  • Using IRB_RC to define useful shortcuts for yourself when navigating around your application with script/console.
  • Efficiently storing model-backed data in constants using class-level ActiveRecord find’s. Example: load all of your states into an Array when the application starts rather than loading them each time a form is displayed that needs to use them.
  • Capistrano multi-environment deployments which allow you to do things like “cap staging deploy” and “cap production deploy”. I’ve been doing this for a while with capistrano-ext but really capistrano-ext isn’t even needed. Every developer using capistrano should be making use of this and a staging environment.
  • Keeping database.yml and other files out of Subversion using a Capistrano after filter when deploying apps.
  • Keeping certain data outside the multiple-release capistrano paradigm by symbolic linking folders within public to subdirectories in shared. This is perfect for establishing a place to upload via FTP without requiring someone to go through the SVN commit and capistrano deploy route. I’ve also used this before but the mechanism described in the book is more elegant.
  • SQL query tracing – finding out where queries are being run and what is going on behind the scenes. Could come in useful when debugging a nasty situation.
  • Using a master/slave database configuration for large applications with Rick Olsen’s masochism plugin.
  • My favorite: Handling complex forms spanning multiple models each with possible one-to-many or many-to-many relationships using the “presenter” pattern. Essentially this allows you to have a layer of design abstraction between the controller and the models whereby you can design a “presenter” which acts as as “manager” of multiple model objects meant to be displayed using the same form. Difficult to explain in full here (buy the book!) but this sounds like a very elegant solution for more data-complex applications. I may do some refactoring with Rarenewspapers.com’s back-end to use this pattern.

The book is still in beta form and there are definitely errors. Hopefully some more recipes will also be added (I’m hungry for more!) before the book is released, but ultimately the knowledge presented in Advanced Rails recipes will be very insightful for professional Rails developers.

New MacBook!

December 28th, 2007 benhughes

This Christmas my parents got me an Apple giftcard which I promptly used to buy a new 2.2Ghz MacBook. With next day shipping, I had it in my hands at 10:30 yesterday morning (27th) – pretty fast!

All day yesterday I was setting stuff up (and to some extent today) and I think I’ve finally got everything moved over. I also invested in 4 gigs of memory from Newegg for only $110. Because of the small screen, I’ve found Leopard Spaces invaluable. I still have quite a bit to learn, but I’m glad I made the switch. I can finally start developing with TextMate.

My New MacBook

Nested URL Parameters

December 20th, 2007 benhughes

One of the great things about Rails is the ability to wire together form logic with extreme ease through Rails’ support of essentially representing hashes through the “object[name]” syntax of URL parameters. Arrays are also supported in a similar manner, making things like many-to-many relationship management cake.

In Rails 1.2 one issue I ran into is that this hash-based access logic cannot be nested when using helpers such as url_for (which is in turned used by helpers such as link_to, etc.) This type of functionality is rather useful when you are trying to encapsulate a set of name-value pairs within one “thing”, such as a “search” which is many criteria => value pairs. For a particularly project of mine I established a pretty nice design pattern for working with searches and results in a very abstract manner, an area of Rails that I generally find underdeveloped with no standard practice.

I was lucky to stumble on a Rails plugin that monkey-patches Rails to support this: nested_params_patch. Information about this plugin is quite sparse but this article does a good job of better-explaining what the plugin does. Essentially it allows you to do things like this:

person_url(:name => {0 => 'Ryan', 1 => 'Kinderman})

Pretty cool stuff! I am always amazed and the kind of plugins and extensions that are possible, all resulting from Ruby’s dynamicism and Rails’ heavily extensible architecture.

User Alert Management with flash and ActiveRecord::Errors

December 11th, 2007 benhughes

A very common paradigm in web application development is presenting the user with some sort of alert or flash message at the top of a page. These alerts are often styled with a background and some sort of icon to the left to indicate what type of error it is. Typically there are a few different types of messages such as “error”, “warning”, “confirmation”, etc., perhaps each type styled differently. Furthermore, such a block typically should support showing a set of messages within one type; not just one string. In Rails the two sources of these messages are usually either the flash object (such as flash[:error]) or ActiveRecord validations errors.

Here is an example of what I mean:

I’ve created a helper method that makes working with these types of messages a breeze.

Essentially it allows you to use the flash object with any of the following keys to specify messages: error, confirm, back, info, and warn (though you can modify it to suit any group of message types). You can either assign a string directly to this which is common, or create it as an array with multiple string messages. The helper will then read these flash objects and display it as a message block that can be styled with CSS, supporting multiple messages per type, separated by type, as well as dynamically grabbing ActiveRecord validation errors off of model object(s) of your choosing and showing those also. The usage of the helper method in your views is as follows

# In Controller:
flash[:confirm] = "Thank you for your input."
flash[:error] = []
flash[:error] << "Wrong Address"
flash[:error] << "Wrong Name"

# In View:
<%= message_block %>

# Or if you want to display errors on @customer
# as well as the flash messages,
<%= message_block :on => :customer %>

# You can even have it watch multiple model
# objects for errors:
<%= message_block :on => [:customer, :order] %>
Here is the helper method that makes this happen:

# Outputs the error messages block.
# The first argument specifies a hash options:
# * :on => :products   Also includes AR validation errors for @products
# * :clear => true     Clears messages after displaying
# * :keep => true      Keeps around messages for next response cycle
#
def message_block(options = {})
  out = ""

  [:back, :confirm, :error, :info, :warn].each do |type|
    next if flash[type].nil? or flash[type].empty?
    flash[type] = [flash[type]] unless flash[type].is_a?(Array)

    out << "<div class=\"container #{type}\"><ul>\n"
    flash[type].each {|msg| out << "<li>#{h(msg.to_s)}</li>\n"}
    out << "</ul></div>\n"

    flash[type] = nil if options[:clear]
    flash.keep[type] if options[:keep]
  end

  if options[:on]
    options[:on] = [options[:on]] unless options[:on].kind_of?(Array)
    models = options[:on].map {|m| instance_variable_get("@" + m.to_s)}.select {|m| !m.nil?}
    errors = models.inject([]) {|b,m| b += m.errors.full_messages}

    if errors.size > 0
      out << "<div class=\"container error\"><ul>\n"
      errors.each {|msg| out << "<li>#{h(msg.to_s)}</li>\n"}
      out << "</ul></div>\n"
    end
  end

  content_tag(:div, out, :id => 'message_block', :class => 'flash')
end

And the CSS code that works with it:

/*** Flash Messages ***/
.flash {

}

.flash ul {
    padding-left: 0pt;
    margin-bottom: 0pt;
    list-style-type: none;
    margin-left: 0pt;
}

.flash ul li {
    background: transparent url(../images/icons/bullets/gt.gif) no-repeat scroll left center;
    margin-bottom: 0.6em;
    padding-left: 1em;
    vertical-align: top;
}

.flash .container {
    padding: 1em;
    padding-left: 5em;
    margin-bottom: 1.5em;
}

.flash .error {
    background: #fcf6d0 url(../images/icons/flashes/error.gif) 1.5em 1em no-repeat;
    border-top: 1px solid #ecd757;
    border-bottom: 1px solid #ecd757;
}
.flash .back {
    background: #e9f3dc url(../images/icons/flashes/back.gif) 1.5em 1em no-repeat;
    border-top: 1px solid #bfcbb0;
    border-bottom: 1px solid #bfcbb0;
}

.flash .confirm {
    background: #e9f3dc url(../images/icons/flashes/confirm.gif) 1.5em 1em no-repeat;
    border-top: 1px solid #bfcbb0;
    border-bottom: 1px solid #bfcbb0;
}

.flash .info {
    background: #dee9f4 url(../images/icons/flashes/info.gif) 1.5em 1em no-repeat;
    border-top: 1px solid #b4c5d5;
    border-bottom: 1px solid #b4c5d5;
}

.flash .warn {
    background: #fcf6d0 url(../images/icons/flashes/warn.gif) 1.5em 1em no-repeat;
    border-top: 1px solid #ecd757;
    border-bottom: 1px solid #ecd757;
}

You may even want to consider writing a before_filter in your application controller that sets the flash types to arrays so you can just add messages to them with the << operator:

class ApplicationController < ActionController::Base
  before_filter :initialize_flash_types

  def initialize_flash_types
    [:back, :confirm, :error, :info, :warn].each {|type| flash[type] = []}
  end
end

Don’t use symbols for route parameters!

December 10th, 2007 benhughes

I’ve ran into this issue more than once: Be sure that you are using strings and not symbols when specifying parameters for routes. Particularly, if you specify a symbol for :action, Rails will fail to see your controller action yet still show your Rails view! This can sometimes be very difficult to diagnose. So, don’t do this:

map.connect '/pages/:slug',
:controller => 'pages',
:action => :show

Do this:

map.connect '/pages/:slug',
:controller => 'pages',
:action => 'show'

HTML-Aware Truncate Text

December 9th, 2007 benhughes

When building a large custom PHP CMS system for DigitalPeach, I ran into a very difficult issue: truncating text but maintaining HTML nested tags correctly. Specifically, we were looking to breaking up large articles composed using FCKEditor into separate pages after a certain character threshold. Once can easily see the problem:

<p>This is a test <strong>with some bold in here</strong>.</p>

Now imaging having to truncate this text to 30 characters, and you end up with this:

This is a test <strong>with

While this example isn’t quite so severe and at worst would only make the rest of the text within the block-level element bold, clearly if we do a truncation that is blind to HTML some serious problems can arise. Furthermore, even if it doesn’t have much practical significance, you are breaking XHTML.

I was lucky to stumble across an excellent article by Mike Burns who describes a Ruby method using REXML’s pull parser that can accomplish this. His example extended the String class, so I modified it to work as a Rails helper all in one method:

def truncate_html(input, len = 30, extension = "...")
  def attrs_to_s(attrs)
    return '' if attrs.empty?
    attrs.to_a.map { |attr| %{#{attr[0]}="#{attr[1]}"} }.join(' ')
  end

  p = REXML::Parsers::PullParser.new(input)
    tags = []
    new_len = len
    results = ''
    while p.has_next? && new_len > 0
      p_e = p.pull
      case p_e.event_type
    when :start_element
      tags.push p_e[0]
      results << "<#{tags.last} #{attrs_to_s(p_e[1])}>"
    when :end_element
      results << "</#{tags.pop}>"
    when :text
      results << p_e[0].first(new_len)
      new_len -= p_e[0].length
    else
      results << "<!-- #{p_e.inspect} -->"
    end
  end

  tags.reverse.each do |tag|
    results << "</#{tag}>"
  end

  results.to_s + (input.length > len ? extension : '')
end

Note that the nested method above is a completely valid use of Ruby, though not widely used.

And now look at what it can do:

truncate_html("<p>Test <strong>bold</strong> done.</p>", 30)
# => "<p>Test <strong>bold</strong></p>..."