Rails gets more mature

Posted by Luke
on Friday, May 02

Rails 2.1 is right around the corner. I’ve been following the new features in Edge Rails and eagerly looking forward to this release. Rails 2.1 includes a number of features that will make developers’ lives easier. Here’s a few of my favorites.

Necessary directories created if they don’t exist

Neither Mercurial nor Git track empty directories. This is a pain with Rails, because you have to create a file in the log directory to make sure it gets created when you check out code, otherwise Rails won’t start. This is no longer needed, because Rails will create necessary directories if they don’t exist.

Time zone support

Time zones are a huge pain in any application, in any language because they are just plain confusing. But ya gotta do it. In Rails, the solution used to be using the TzTime and TzInfoTimeZone plugins. Rails 2.1 adds support for tracking Time objects with their time zone. This is going to make everyones’ lives a lot easier. Check out Geoff Buesing’s in-depth tutorial.

Partial updates and “dirty” tracking

Two features that I knew and loved in our home-brew ORM from my former life as a Java developer have made it into Rails.

With dirty objects you can know if you need to persist an object, and which attributes have changed, and what an attribute’s previous value was. This will be great for user messages and validations!

In Rails 2.1, ActiveRecord can update only the attributes which have changed. This can (sometimes) put your objects into an inconsistent state, but partial updates improve performance, especially when you have big TEXT or BLOB attributes that haven’t changed. Use optimistic locking to prevent users from stomping on each others’ changes.

Timestamped migrations

With all this distributed SCM going on, the classic problem of messed up migrations gets way worse. I talked about solutions to this in my talk at acts_as_conference, one of which was timestamped migrations. Timestamped migrations allow interleaved migrations. As long as those migrations don’t conflict with each other, they can be applied in any order. This has been added to Rails. Nice!

Better gem dependency and unpacking

I am a big fan of the vendor everything approach to gems because I got burned way too many times by missing gems.

But it doesn’t always work (for example, gems which must be natively compiled are a problem), and you have to install one of the various vendor everything plugins—and everyone seems to use a different one. In Rails 2.1, gem unpacking is built in with rake gems:unpack GEM=gemname. (more info)

And for those gems that don’t work, you can list them as a dependency. Your app will fail to start if the gem is not installed. Fail early, fail often!

Text helpers usable outside the view

You can now use helpers without including them into your class. Hurray!

5 little-known Rails methods

Posted by Eric
on Wednesday, April 23

While the next release of Rails appears to be coming up, there’s still plenty of small, useful features from previous releases that aren’t widely used.

A few of my favorites:
  1. query_attribute
  2. polymorphic_path
  3. debug
  4. rake -T `query` ( Not Rails specific, but still handy! )
  5. extract_options!

1. ActiveRecord’s query_attribute

Query methods are available for each of a record’s attributes, providing for a cleaner way to check for the presence of an attribute.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# == Schema Information
# Schema version: 17
#
# Table name: users
#
#  id                    :integer(11)     not null, primary key 
#  first_name            :string(255)     
#  last_name             :string(255) 

# Original
class User < ActiveRecord::Base
  def named?
    !first_name.blank? && !last_name.blank?
  end
end

# Refactored to use query_attribute
class User < ActiveRecord::Base
  def named?
     first_name? && last_name?
  end
end

2. Indifferent links with polymorphic paths.

Rails has polymorphic edit/new/formatted path routing available out of the box. Providing an array will namespace the path with those array parameters. Available Methods: (edit|new|formatted|)polymorphic_path(record_or_hash_or_array)

1
2
3
4
5
6
7
8
9
10

# Before:
<% if @record.is_a?(User) %>
<%= user_path(@record) %>
<% elsif @record.is_a?(Friend)
<%= friend_path(@record) %>
 ... etc.

# After:
<%= polymorphic_path(@record) %>
Quite a few options are supported, and other Rails methods take advantage of polymorphic routing:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Paths can be namespaced:
#=> admin/users/5/edit
edit_polymorphic_path([:admin, @record])

# Polymorphic urls are also internally used by helpers:
# redirects to store_path(@store)
redirect_to @store
  
# builds a form with an action to 'new_admin_stores_path'
#=> <form action="admin/stores/new" ... />
form_for([:admin, Store.new])

# <a href="/stores/5">A store in Minneapolis, MN</a>
link_to @store.name, @store

3. debug

Especially useful when starting out a project, this is quick way to understand what objects are being used in the view.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


<%= debug @user %>

# Yields this in the view:
# - !ruby/object:User 
#  attributes: 
#    salt: 7be4287a1b27426fa6e5b6d733c707dd66425e82
#    updated_at: 2008-04-22 19:01:23
#    crypted_password: abb611def895dac923ba8ea59a78451f77473d5e
#    id: "1"
#    first_name: Eric
#    last_name: Chapweske
#    created_at: 2008-04-06 01:45:33
#  attributes_cache: {}

4. rake -T task

This is a handy Rake feature, and not limited to Rails. Can’t remember the exact syntax for a particular rake task? Trim the results generated with `rake -T` with an optional search parameter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

$rake -T

rake annotate_models                 # Add schema information (as comments)...
rake audit:purge                     # Removes Audit records older than 2 m...
rake db:abort_if_pending_migrations  # Raises an error if there are pending...
... etc.
rake tmp:sockets:clear               # Clears all files in tmp/sockets

// Searching by the task's name

$rake -T db:migrate:r

rake db:migrate:redo   # Rollbacks the database one migration and re migrat...
rake db:migrate:reset  # Resets your database using your migrations for the...

5. extract_options!

While not needed very often, Rails comes bundled with a method to extract the options from methods that utilize the splat operator. This method removes the last object from an array if it’s a Hash, otherwise an empty hash is returned.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


class Story < ActiveRecord::Base

  # Example: 
  # Story.published_and_tagged_with('deep', 'thoughts', :order => 'created_at desc') 
  # The generated options for this method look like this: 
  #=> { :include => :tags, :order => 'created_at desc' }
  def self.published_and_tagged_with(*tag_names)
    options = tag_names.extract_options!
    options[:include] ||= :tags
    
    ...
  end
end

References

I wasn’t able to find any write ups on the above methods, so reading the source code may be the best path if you’re curious about their exact implementations.

Auto-escaping HTML with Rails

Posted by Luke
on Monday, January 28

One of the things I don’t like about Rails is that it doesn’t auto-escape HTML in user input. Forget one h call in your template and you’re screwed. Worse yet, before Rails 2.0, strip_tags and sanitize were flawed. Fortunately that’s been fixed. Django added auto-escaping even though it was a backwards incompatible change, but so far there doesn’t seem to be similar movement on the Rails front.

But I’m all about automating manual processes. So let’s fix this problem.

Sanitize before saving or before displaying? Or both?

Should you sanitize text before saving it or before displaying it?

It’s nice to not need to worry about doing anything extra in your views. However, if a field escapes your notice, you may be open for an attack.

I think your first line of defense should be model-level sanitization, but auto-escaping HTML is good backup. Doing both covers your bases at a cost of extra processing.

Introducing xss_terminate

xss_terminate is a plugin in that makes stripping and sanitizing HTML stupid-simple. It’s install and forget. And you can forget about forgetting to h() your output, because you won’t need to anymore. It’s based on acts_as_sanitized by Alex Payne but updated for Rails 2.0, and with some new features.

I like acts_as_sanitized but it’s not being maintained any more so Alex gave me the OK to take his code and do something different with it. Here’s what makes xss_terminate different:

  • It works with Rails 2.0.
  • It’s automatic. It is included with default options in ActiveReord::Base so all your models are sanitized. Period.
  • It works with migrations. Columns are fetched when model is saved, not when the class is loaded.
  • You can decide whether to sanitize or strip tags on a field-by-field basis instead of model-by-model.
  • HTML5lib support if Rails’s HTML parser isn’t doing it for you.

Here’s how you use it.

To install: script/plugin install http://xssterminate.googlecode.com/svn/trunk/xss_terminate

Strip HTML tags from all the fields in a model

1
2
class Article < ActiveRecord::Base
end

Done. All models have tags stripped by default.

Sanitize HTML from some fields

1
2
3
class Article < ActiveRecord::Base
  xss_terminate :sanitize => [:body]
end

Use HTML5lib to sanitize HTML from some fields

HTML5lib is a new library for parsing HTML for Python and Ruby. Its goal is to parse HTML like browsers do, so it’s very fault-tolerant. If you want to use it, gem install html5 and use the :html5lib_sanitize option. This is thanks to code by Jacques Distler.

1
2
3
class Article < ActiveRecord::Base
  xss_terminate :html5lib_sanitize => [:body]
end

But I don’t want to strip HTML at all from that field!

1
2
3
class Article < ActiveRecord::Base
  xss_terminate :except => [:title, :body]
end

Putting it all together

And of course, you can put these options together. Remember, fields are stripped of tags by default, so that’s assumed unless you override it.

1
2
3
class Article
  xss_terminate :except => [:author_name], :sanitize => [:title], :html5lib_sanitize => [:body]
end

Report bugs at the xss_terminate Google Code site.

Extra credit: Use Erubis

Erubis catches 80% of HTML escaping screw ups by making them impossible. You can use it in conjunction with xss_terminate or other XSS plugins to give yourself an extra layer of protection. (See our post on setting up Erubis with Rails 2.0.)

With Erubis, code like <%= "<script>alert('pwnd')</script>" %> can be auto-escaped.

However, all Rails helpers which generate HTML must be called with <%== %> so the HTML is not escaped. This leaves an opening for attacks like this:

<%== link_to user.name, "/some/url" %>

If user.name contains XSS you’re pwnd.

So while Erubis is a marked improvement over Erb it’s not a cure-all. That’s why I like to use both approaches.

Other approaches

There’s been a lot of discussion about Rails and XSS lately, so I’m hopeful that the situation will get better. Here’s a couple other XSS protection projects you can check out:

  • SafeERB – Throws exceptions if you try to display tainted strings. Call h() to untaint.
  • xss-shield – automatically h() strings unless marked as “safe”.
  • sanitize_params – strip HTML from your parameters before they hit your models.
  • AntiSamy – another whitelist-based approach (not available for Rails)

Also, check out Is your Rails App XSS Safe? and Never Untaint by Stu Halloway and Jacques Distler’s posts about making Instiki XSS-safe: XSS and XSS 2 (these are must read).

Rendering with Erubis and Rails 2.0

Posted by Eric
on Monday, December 10

Update: ActionView has been refactored in Rails 2.0.2, making Erubis’ Rails helper, and the “Create an Erubis Initializer” section of this article, obsolete. See the comments for a Rails 2.0.2 compatible initializer. Thanks for the tip, Jason!

Erubis is a drop in replacement for Erb. Among its many features are a few notable improvements in terms of speed and security (it optionally supports auto-html escaping).

Sample Erubis Syntax:
1
2
3
4
5
# Erubis with auto HTML escaping enabled:

Hello, <%= current_user.name %> # equivalent to h(current_user.name)

<%== render :partial => 'user' %>

Installing Eribus:

1. Install the gem


gem install erubis

2. Create an Erubis initializer

app/config/initializers/erubis.rb
1
2
3
4
5
6
7
8
9
10
11
# Via http://www.kuwata-lab.com/erubis/users-guide.05.html#topics-rails
# The above link also references an optional patch that can be applied.

require 'erubis/helpers/rails_helper'

# These are optional settings:
Erubis::Helpers::RailsHelper.init_properties = { :escape => true, :escapefunc => 'h' }

# Erubis::Helpers::RailsHelper.engine_class = Erubis::Eruby # or Erubis::FastEruby
# Erubis::Helpers::RailsHelper.show_src = false
# Erubis::Helpers::RailsHelper.preprocessing = true

3. Create custom rescue templates

The default Rails debug views need to be slightly modified to support Eribus. This problem only pops up in a few spots, but Eribus doesn’t handle inline statements:

1
2
3
4
5
6
7
# Default Rails sample:
<%= request.parameters["controller"].capitalize if request.parameters["controller"] %>

# Erubis compatible rewrite:
<% if request.parameters["controller"] %>
<%= request.parameters["controller"].capitalize %>
<% end %>

If auto-escaping is enabled, all instances of <%= need to be replaced with <%== and <%=h replaced with <%=.

Step 1: Download these auto escaped, Eribus-friendly templates and put them in app/views/rescues

Step 2: Redefine the rescues path to point to the modified templates:

controllers/application.rb
1
2
3
4
# For Erubis compatible debug templates  
def rescues_path(template_name)
  "#{view_paths.first}/rescues/#{template_name}.erb"
end

Using Erubis

Auto escaped Erubis vs Erb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Erubis doesn't handle inline parsing well.
# While in Erb, this would work:
# <%=h status = current_user.status if returning_user? %> 
# It needs to be broken out in Erubis:

<% if returning_user? %>
  <%= current_user.status %> # Auto HTML escaped
<% end %>
                                                                          
Here's a list of your friends, <%= current_user.first_name %>        # Auto-escaped
<ul>
  <%== render :partial => 'friend', :collection => @friends %>       # Not escaped
</ul>
<p><%== submit_tag "Add a friend", :class => "button" %></p>         # Not escaped
<% end %>
A few things to remember:
  • Erubis doesn’t handle inline statements well
  • If auto escape is enabled, use the <%== operator when rendering partials and helpers
  • Update app/views/layout templates
References

Textmate: remove unnecessary files from Rails project

Posted by Jon
on Tuesday, November 13

Have you ever done a cmd-T or a global find in Textmate while working on a Rails project, and found more noise than signal in the results? For example, when trying to navigate to the routes.rb file, here is what I see:

routing.rb
routes.rb - config
routes.rb - configs
routes.rake
routing_test.rb
routing_error.html
routing_assertions.rb

This is because Textmate loads my entire vendor/ directory when I open up a project, including the entire Rails source. I can find the right file (it is routes.rb - config), but this breaks my focus and keeps searching and navigation from being transparent.

Similarly, log files are loaded into Textmate by default, which is terrible if you want to search across the entire site; I’ve had searches take 60 seconds or crash Textmate just because they were digging through enormous log files.

There is a simple way to fix this. Go to Preferences, and choose “Advanced” and then “Folder References”. You’ll see two regular expressions. They both start with a !, so any files that match the pattern will be excluded from Textmate. To stop searching through your vendored copy of Rails, just add this after the first parenthesis in the folder pattern:

vendor\/rails|

So the front of my folder pattern now looks like this:

!.*/(vendor\/rails|\.[^/]*

And to stop including log files, add this after the opening parenthesis in the file pattern:

.\.log|

The | is an “or” separator, so if you want to add more patterns, separate them by pipes. Pretty simple.

You can do quite a bit more, like excluding binary files (.jpg, .png, etc.), excluding plugins, etc. Just follow the same patterns as above.

iPhone subdomains with Rails

Posted by Luke
on Thursday, November 08

iPhone! It seems like everyone has one, and those who don’t have one are talking about it. (I fall into the latter category.)

I recently attended an Apple iPhone Tech Talk with some of my colleagues from Slantwise. It was well worth it. I highly recommend going if the talk comes to your area. If you can’t attend, you can watch the videos online. Getting into the nitty-gritty of how to develop for the iPhone and iPod Touch was very interesting, but to me the most useful aspect of the class with the information on the iPhone web application user interface guidelines.

Most examples I’ve seen for how to do a special view for the iPhone suggest something like this:

1
2
3
4
5
6
7
8
9
10
class ApplicationController < ActionController::Base  

  before_filter :adjust_format_for_iphone

  def adjust_format_for_iphone
    if request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(iPhone|iPod)/]
      request.format = :iphone
    end
  end
end

However, Apple’s user interface guidelines for the iPhone suggest against doing user agent sniffing. The reason is that iPhone users are used to being able to use the entire web. They don’t want a limited subset.

Another problem is that when Apple releases a new device, your code will need to be updated to work with it. This actually happened when the iPod Touch was released. Some iPhone sites didn’t work on the iPod Touch because (unlike the code above) they only sniffed for “iPhone”.

When I was at the Apple iPhone Tech Talk, Apple suggested the best way to develop web applications for the iPhone was to provide the full version of your site, with a link to the iPhone web app. The iPhone version should focus on discrete functionality, and look like a native iPhone application. But if an iPhone user ever needs to use the “real” site, it’s just a clicks away. Examples of sites doing this include Facebook and Amazon)

Fortunately, this is still easy to do with Rails.

1
2
3
4
5
6
7
8
9
10
class ApplicationController < ActionController::Base  

  before_filter :adjust_format_for_iphone

  def adjust_format_for_iphone
    if request.subdomains.first == "iphone"
      request.format = :iphone
    end
  end
end

You can test that your subdomain detection works with something like this:

1
2
3
4
5
def test_hitting_app_using_iphone_subdomain_should_set_iphone_virtual_mime_type
  @request.host = "iphone.test.host"
  get :index
  assert_equal :iphone, @request.format.to_sym
end

This is kind of a drag to develop with, so when not in production mode, I sniff based on the user agent like the old way.

1
2
3
4
5
6
7
8
def adjust_format_for_iphone
  if request.subdomains.first == "iphone" || 
     (RAILS_ENV != "production" && 
      request.env["HTTP_USER_AGENT"] && 
      request.env["HTTP_USER_AGENT"][/(iPhone|iPod)/])
    request.format = :iphone
  end
end

With this, I can use iPhoney to test my code on localhost, but the sniffing isn’t used when deployed.

For those times when you do need user agent detection, Apple recommends testing the “Mobile/XX” part of MobileSafari’s user agent string. This will work across iPhone, iPod Touch, and future MobileSafari devices.

Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/XX (KHTML, like Gecko) Version/ZZ Mobile/WW Safari/YY

Here’s an AbstractRequest#iphone? method. You can use in in your views to display a message to iPhone users telling them about your iPhone-optimized site or web application (like Amazon does). But I’m not sure if this is the “Rails way” to do this. Let me know in the comments.

1
2
3
4
5
6
7
module ActionController
  class AbstractRequest
    def iphone?
      self.env["HTTP_USER_AGENT"] && self.env["HTTP_USER_AGENT"][/(Mobile\/.+Safari)/]
    end
  end
end

And of course, I used the above method to refactor my adjust_format_for_iphone method.

For more on this topic, check out the iPhone Dev Center. You have to be an ADC member to look at the content, but signing up is free.

Update: Check out Ben’s Slash Dot Dash article on iPhone on Rails – Creating an iPhone optimised version of your Rails site using iUI and Rails 2 for some new tips and tricks.

Bringing the Rails Magic to Facebook

Posted by Eric
on Friday, November 02

While there’s a few plugin options for the Rubyist looking to write a Facebook application, none of them quite fit our needs. I opted to write one for internal use at Slantwise. Why? A fundemental difference between this code and the publicly available solutions is that its Rails-centric.

If you’re not planning on writing your app in Rails, this isn’t the library for you. The benefits to the Rails programmer is that they now have a Facebook interface that’s borderline indisguishable from other Rails code—meaning its understandable, enjoyable, and doesn’t require hours of pouring through Facebook’s API documentation.

Ruby, where art thou?

This first sample shows some of the library’s low-level functionality, and its pretty similiar to the other solutions out there. It also demonstrates the inherent problems with simply wrapping API calls.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  # Retrieves photos from the first album that's found for the current user on Facebook
  # Then publishes some of the photos as a news update in Facebook
  ...
  #Retrieve the photos
  recommended_album   = Facebook::API::Albums.get(:uid => current_user.facebook_uid).first
  @recommended_photos = Facebook::API::Photos.get(:aid => album[:aid])

  # Assign all the necessary API params for publishing to Facebook.
  # This is a more complex (and abbreviated) API call
  # A typical update call will take at least a few lines of code
  feed_body_template = render_to_string(:partial => 'facebook/_body_template')
  feed_body_general  = render_to_string(:partial => 'facebook/_body_general')
  ...
  recommended_photos_feed = { :actor => current_user.facebook_uid, 
                              :body_template => body_template,
                              :body_general   => ... ,
                              ... }
  
  #Publish the feed to Facebook
  Facebook::API::Feed.publish_templatized_action @recommended_photos_feed

Direct API calls are great in some instances, but not in most. Writing something like the following could easily take someone new to the Facebook API hours to figure out. It also takes the magic out of working in Rails—increasing development time and developer frustration and ultimately resulting in a lesser product. Let’s bring that magic back and put a smile on our developer’s face while we’re at it:

Hello, old friend

1
2
3
4
5
  
  recommended_album   = current_user.facebook.albums.find_by_name 'Halloween'
  @recommended_photos = recommended_album.photos

  update_facebook 'recommended_photos.feed'

The first line of code is a Facebook API call. It utilizes a basic ActiveRecord connection that’s adapted to run through the Facebook API, so the results behave exactly the same as any other ActiveRecord request.

The update_facebook method is a specialized version of render that looks for a template named ‘recommended_photos.feed’, fills it with data, and sends it to Facebook. In this case, the ’.feed’ extension maps to the Facebook API call Feed.publishTemplatizedActionOfUser. The rendering action is easily configurable to support any extension/API call combination.

Interested?

The plan is to release a development version of the plugin within the next week or two to iron out any glaring bugs, followed very shortly thereafter with a production version that you can freely use in your projects. I’ll announce the plugin release here when it’s available.

Get Involved

While I think I’m off to a good start, I’m looking for help. I’m on the look out for highly useful features. If you’re developing a Facebook application and have any problem areas, send me an example of some problem code and I’ll look into incorporating a solution into the plugin.

My First Rails App

Posted by Luke
on Saturday, October 27

I’ve recently have the “opportunity” to do some work on the first Rails app I developed professionally, as well as an existing codebase that’s in a similar state.

We’ve all been there. Trying to understand old code, refactoring, adding features and tests. It’s painful. And considering how much Rails has changed in the last 2 years, it’s no wonder that working with apps written for older versions is no fun.

Here’s a few “worst practices” that I’ve encountered in my own and others’ old code:

  • Using url_for instead of named routes and RESTful routes. Just say no to relying on Rails default, implicit routing. I even delete the default route from routes.rb.
  • <% @objects.each do |obj| %>...<% end %> instead of <%= render :partial => 'object', :collection => @objects %>
  • Lots of if blocks in application.rhtml instead of creating new layouts.
  • Not using content_for :whatever to insert code in layouts.
  • Not following Rails convention, like misnamed controllers: UserController instead of UsersController
  • Practically any use of scaffolding (my beef with scaffolding: code generation results in a lot of views you ultimately won’t need, which then get in your way.).
  • Not using Rails association methods: Thingy.find(owner.thingy_id) instead of owner.thingy
  • Similarly, not using the built in create and build methods on associations: Employee.create(:employer => employer, :name => "Bob") instead of employeer.employees.create(:name => "Bob")
  • Security issues. XSS and attributes that should be attr_protected first among them.
  • Bad or non-existent tests.
  • Deprecated code. It probably wasn’t your fault, but given the pace of change in Rails, working with an old app almost certianly means working with code that’s now deprecated.

Do you have any of your own favorite newb mistakes? Add ‘em in the comments.

Photo by chaim zvi.

Rails developers: experts or script kiddies?

Posted by Jon
on Thursday, July 05

Sunjay Pandey of AlterThought has an an article that makes a case against Ruby on Rails. I usually try to stay out of these discussions; every technology has advantages and disadvantages, and I am well aware of the good (quality, speed, testing, maintainability, small community) and the bad (Ruby needs a good VM, Rails is young, small community) when it comes to Rails.

So after a pro-Rails post, Sunjay decided to outline the problems with Rails. It isn’t a very good presentation of Rails’ problems, and yet Sunjay’s focus is interesting. He focuses on the Rails community and Rails developers when discussing what is wrong with Rails. Here is the core of his argument:

The unfortunate reality of the RoR movement and market is that there are a number of below average soloists passing themselves off as solid developers due to the level of demand.

and

(1) Rails helps bad coders write unscalable, unmaintainable, unmentionable code faster, ergo (2) Rails helps organizations fail faster.

The first quote is interesting. The second is completely wrong.

What is the developer quality of the Rails world?

(See Dan Grigsby’s recent article on the Rails contract market for prerequisite reading.)

Rails largely draws its market share from PHP and Java. Rails apps can be written as quickly as PHP, and can be as robust and maintainable as Java. And developer satisfaction exceeds both.

In my experience, the Rails community is extremely strong at the top, like the best of the Python, Java, and Lisp communities. People like Dave Thomas set the tone of the Ruby and Rails community, and you couldn’t ask for a better tone-setter. Most professional Ruby developers that I know are smart, personable, and pragmatic – the kinds of folks that you want on your development team.

At the same time, there are a more and more mediocre Rails developers watering down the community. This wasn’t true two years ago, but as Rails grows, it attracts more and more newbies. There is nothing wrong with this; Rails is pretty welcoming to newbies, and today’s newbies are tomorrow’s experts.

If there is a problem with the quality of work coming out of the Rails world, the problem lies with demand. Rails allows applications to be written more quickly, and therefore more cheaply. This means that many businesses who are looking for a cheap option look to Rails. Not content to save money through the efficiency of Rails, they also look for cheaper developers. In essence, they create a demand for $40/hour companies and $10,000 social networks. And you know how markets go; if the demand is there, someone will meet it.

Newbie Rails developers aren’t a bad thing. Newbie Rails developers passing themselves off as experienced Rails developers, because a client wants top quality work for $40/hour, are a problem.

So what does this mean? Don’t hire a $40/hour company unless you want $40/hour work. Don’t hire someone with a thin portfolio unless you’re willing to accept the risk. Don’t hire anyone who claims to be a Ruby rockstar, ninja, pirate, whatever. If you want a well-written app, and if you’re dealing with complex problems, hire a good developer with good experience, and pay them what they’re worth. Like the authors of Railspikes. (Shameless plug – sorry!)

Does Rails encourage bad code?

As I said, the Rails community is mostly a mix of ex-Java developers and ex-PHP/Perl developers. PHP isn’t all bad, but it is unfortunately a magnet for bad code. This could be because many bad coders choose PHP, or because PHP has really low barriers for entry, or because PHP itself encourages bad development practices. I suggest that it is a combination of these. The end result: PHP does not have a culture of high programming standards. Design patterns, unit testing, etc. are on the margins of the PHP world. There are good PHP developers, and you can write good code with PHP, but PHP (and the PHP community) isn’t going to help you out too much.

Sunjay assumes that the latter is true of Rails, but he is wrong. The Rails framework and the Rails community are both built on a culture of good programming habits.

  • Unit tests? Built in and highly encouraged. Rails all but screams at you if you don’t test your code.
  • Deployment automation? Capistrano takes about 10 minutes to configure and works beautifully.
  • Source control? Rails assumes you’ll use source control. There are rake tasks that automatically add new classes to your SCM, and Capistrano pretty much requires it.
  • Code generation? Check.
  • Web services? You get REST for free.
  • Design patterns? 80% of Rails is an implementation of MVC and ActiveRecord. ActiveRecord works like a charm for the vast majority of applications, and MVC is a beautiful way to structure web application code.
  • Platform? Stay away from Windows. OS X, Linux, BSD, Solaris, work great. (This is “checkmate” when it comes to good programming habits.)

Rails pushes developers in the right direction. Give Rails to a bad coder, check back in two years, and you’ll find a good developer.

So Rails doesn’t “helps bad coders write unscalable, unmaintainable, unmentionable code faster”. It encourages you to write scalable, maintainable, mentionable code. If you do the opposite – no tests, logic in your views, duplication – it’s because you’re misusing Rails.

Profile of a Rails community

I am fortunate to be involved with the Ruby Users of Minnesota. Most of my opinions about the Rails community come from my experience with RUM (along with reading blogs and attending conferences). Based on these experiences, here is my impression of the Rails world.

  • Rails is full of really good Java developers who got sick of writing XML. Like: the folks who would be leads on most Java teams; the folks who choose (and enjoy) the hard problems; the folks who know what is right with Java, what is wrong with Java, and what other options exist.
  • The average Rails developer has pretty good business sense. Rails lets you code pretty closely to the business problems. If you can write an e-commerce engine in a few weeks, the ratio of time spent thinking about interaction and user experience compared to time spent writing low-level classes is pretty high. So it helps to have good business sense.
  • Similarly, Rails usually draws developers with good people skills. (This might be related to the previous point.)
  • Most Rails developers are interested in technologies beyond Rails. Functional programming, for example, is pretty hot at our local Ruby group.
  • Most Rails developers made a conscious choice to switch to Rails from J2EE/Perl/PHP/whatever. So they usually aren’t technology zealots, and they usually see the other side clearly. At our last two meetings, we had a Python developer present Django, and a Groovy developer present Grails, and both were very well received.

That’s the Minnesota Ruby community in a nutshell. If RUM is a microcosm of the larger Rails world, and I think that it is, then the Rails community is a pretty interesting place to be.

Video Transcoding, part 3: Asynchronous Processing (overview)

Posted by Jon
on Thursday, May 17

(This is part 3 in a series on video transcoding. Parts 1 and 2 covered video formats and codecs, and transcoding tools, respectively.)

Ruby on Rails is a great technology that gives you a lot for free. You get ORM, MVC, templating, HTML helpers, URL rewriting, database schema management, a development web server, prototype, script.aculo.us, deployment automation, a unit test framework, etc. etc. etc. But what you get falls into two basic categories: tools to handle a HTTP request, and tools to make the application easier to manage. In other words, Rails helps you out when something is either triggered directly by an HTTP request, or when it is triggered directly by a developer. This is because the Rails environment fires up and tears down with every HTTP request.

Unfortunately, a video transcoding system can’t be run in either of these ways.

First, video transcoding can’t be done within the space of an HTTP request. Transcoding jobs can take several minutes (or hours), and you can’t expect your users to wait that long. If a request takes longer than a few seconds, a significant number of users will cancel the request. Beyond this, since Rails isn’t thread-safe, every video transcoding job would cause a Mongrel instance to block.

Second, video transcoding could theoretically be triggered manually by an operator, but this solution isn’t responsive or scalable. What happens when your application takes off, and you have dozens or hundreds of files per day?

In my next few posts, I will examine three approaches to asynchronous processing, and will discuss three ways to host your asynchronous system. The use case will be video transcoding, but the approaches themselves could be used for just about any time-consuming action: expensive calculations, large PDF creation, data processing, etc.

1. Database polling with a daemon – This is the simplest approach, and it isn’t a bad one. All you need is one or more transcoding servers with access to your main Rails application database, and maybe some shared disk space. The transcoding servers query the database for unassigned jobs, and the first server to select the job takes it. Then, when the work is done, the transcoding servers update the database with the new state.

2. Message queue polling – Instead of polling a database, this solution uses a message queue (like Amazon SQS). The base application passes a message to the message queue announcing the new job, and the transcoders poll the queue looking for jobs. This approach is a little more complex than the first approach, but is a little more secure, robust, and scalable.

3. Reactor-pattern system – This solution doesn’t involve polling at all. Instead, a controller accepts jobs and assigns them directly to individual workers. This approach is the most complex of the three, but will satisfy the purist’s desire to avoid polling.

I’ll discuss each of these approaches in their own articles in detail. There certainly are other approaches; if you have a favorite that you don’t see here, post a comment.

Finally, I’ll look at three ways to host these approaches: local to your main application, in its own dedicated hosting environment, and using Amazon Web Services.

Stay tuned for the next post. I’m at RailsConf right now, but I’ll try to get something posted within the next few days.

AJAX partial DOM posting with link_to_remote

Posted by Casey
on Tuesday, April 17

One of my favorite little AJAX tricks is posting only a few fields of the DOM with link_to_remote.

The real world application of this is when you have a composite object that needs to be created in the process of creating your main composing object. It can also be helpful when you have a dynamic interface with hidden divs within one main form and you don’t not want to pass the whole form via xhr (it could be a multipart request with a file selector).

Here is how to submit only one DOM element’s children form inputs:

1.Define the DOM element you want to submit
1
2
3
4
5
6
7
8
9
10
11
12
<div id="remote_message" style="display:none"></div>

<div id="create_input">
        <label>Movie name</label>
        <input type="text" name="create_movie_name" id="create_movie_name" value="" />
</div>

<%= link_to_remote "Create movie", 
        {:url=>'/movie/create',  :submit=>"create_input",  
                :success=>'handleCreateSuccess(request);',  
                :failure=>'handleCreateFailure(request);' }, 
        {:id=>'create_movie_link_id'} %>

The important thing to note is the :submit=>‘create_input’ which defines the DOM element whose children will be serialized and passed to the controller on submit. Also notice we haven’t defined an HTML form. Prototype is smart enough to serialize any DOM structure, not only forms. This could just as well be inside a form, but only the DOM element we specify will be sent to the server.

2. A standard controller to handle the post
1
2
3
4
5
6
7
8
9
class MovieController < ApplicationController

  def create
    return unless request.xhr? && request.post?
    # do stuff
    render :inline => "'#{params[:create_movie_name]}' was created"
  end

end
3. Handle the response with javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/javascript">
//<![CDATA[
        function handleCreateSuccess(request) {
                showMessage("Success! " + request.responseText);
        }
        function handleCreateFailure(request) {
                showMessage("Problems creating that movie: <br/>" + request.responseText);
        }
        function showMessage(message) {
                $('remote_message').show();
                $('remote_message').innerHTML = message;
                new Effect.Highlight('remote_message');
                new Effect.Fade('remote_message', {duration: 10})
        }
//]]>
</script>
And that’s it. Of course you don’t need to use link_to_remote, you could just use prototype's Ajax.Request()
1
2
3
4
5
new Ajax.Request('/movie/create', 
    {asynchronous:true, evalScripts:true, 
        onFailure:function(request){handleCreateFailure(request);},
        onSuccess:function(request){handleCreateSuccess(request);}, 
        parameters:Form.serialize('create_input')}); 

Using this technique you are no longer forced to do full form submissions when you only want a small bit of data which will lead to a more dynamic and ‘snappy’ user experience.