Controller Code Smell in the Wild
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
endThe 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.
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
endAll 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.