Controller Code Smell in the Wild

Posted by Bob Showalter Thu, 21 Jun 2007 20:37:00 GMT

One of the trends you should be practicing is keeping unnecessary code out of your controllers. Here’s a real-world example of a controller Code Smell that I found in an application I’m doing maintenance on.

Here’s the original controller method:
  def clone_billing_address
    @customer = Customer.find(params[:id])
    l = Location.new
    l.address = @customer.address
    l.addr2 = @customer.addr2
    if @customer.is_commercial? then location_name = 'Main Building' else location_name = 'Home' end
    l.name = location_name
    l.city = @customer.city
    l.state = @customer.state
    l.zip = @customer.zip
    l.save
    @customer.locations << l
    l.customer = @customer
    l.save
    @customer.save
    redirect_to :action => 'show', :id => @customer
  end

The purpose of this action is to take some information from the Customer record and create a Location record, which is then linked to the Customer.

The smell is all the @customer method calls. That’s a hint that the Customer object should know how to clone itself. Think in terms of the “Tell, don’t ask” principle. Instead of asking the Customer object for a bunch of details about itself in order to create a Location, tell the object to create a location.

Here’s the refactored method:
  def clone_billing_address
    @customer = Customer.find(params[:id])
    @customer.create_default_location
    begin
      @customer.save!
    rescue
      flash[:warning] = "Unable to clone billing address: #{$!}"
    end
    redirect_to :action => 'show', :id => @customer
  end

All the logic for creating the location has been moved to the Customer model. Note that the original method didn’t do any error checking, so I added some.

Comments

Leave a response

Comments