Minimize or disable WEBrick logging
I wrote a simple application today that used WEBrick servlets to serve up some content, and I wanted to minimize the logging that WEBrick puts out.
There are two kings of logging used by WEBrick:
- Server logging, which is controlled by the
:Serverparameter passed toWEBrick::HTTPServer.new. This uses syslog-style log levels. - Access logging, which is controlled by the
:AccessLogparameter. This logs each request, and is similar to the Apache access log.
The default server log level is INFO, but I wanted to change it to WARN. I also wanted to disable Access logging altogether.
include WEBrick
server = HTTPServer.new(
:Port => 8000,
:Logger => Log.new(nil, BasicLog::WARN),
:AccessLog => []
)autotest errors after migration?
If you generate a new model or run a migration that makes changes to your database, autotest will probably start reporting errors.
For instance, if you generate a new model, edit the migration and then rake db:migrate, you might see something like this:
ActiveRecord::StatementInvalid: Mysql::Error: #42S02Table 'sample_test.widgets' doesn't exist: DELETE FROM widgetsautotest is really smart, which is great. But this one trips it up a bit. The problem is that autotest is running your new widget_test.rb, which is trying to load your new Widget fixtures. However, rake db:migrate only affects your production database, not your test database.
The fix is simple:
- Run
rake db:test:prepare. This applies the current development schema to your test database. - Press Ctrl-C (once) in your autotest window. That tells autotest to restart itself and run the full test suite.
Write at least a simple functional test for each of your actions
If you’re like me, you focus on writing unit tests more than functional tests. Most of the key business logic should be in your models anyway, and it’s easier to test at that level.
Nevertheless, it’s a good idea to at least write a basic functional test for each action to make sure the action at least runs through without any exceptions.
If you run autotest (which is a great tool), or at least run rake:test before any commits, these simple tests can catch boneheaded mistakes like one I made today.
I modified a controller and added an instance varible, which I then referenced in a partial. Everything worked fine and it looked good in the browser, so I committed it.
Unfortunately, I stupidly forgot that the partial was used in another context, and that action promptly broke, because I didn’t create the instance variable there. As it turns out, the proper fix was to move my instance variable out of the partial and into the main template.
A simple functional test on each action would have revealed my mistake right away.
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.
Getting on the bandwagon
Hey, all the cool cats are blogging on Rails, so here’s my go at it…