You are currently browsing the monthly archive for November, 2008.
If you develop Rails applications, you’re probably used to seeing this sort of thing in your log files:
Really, the only important thing there (as far as helping me find the source of the error) is the very first line of the backtrace: ActiveRecord::StatementInvalid (SQLite3::SQLException: no such table: posts: SELECT * FROM "posts" ):. But Rails throws in another 55 lines of backtrace information, just in case I have exposed a bug somewhere in Active Record or Action Pack or the dispatcher or Mongrel or Rack or even the initial script/server command. In most cases, that’s just noise.
Rails 2.3 (inspired by Thoughtbot’s Quiet Backtrace plugin) is smart enough to just shut up about the parts I don’t care. Here’s the default Rails 2.3 log in the same situation:
Processing PostsController#index (for 127.0.0.1 at 2008-11-29 08:12:31) [GET] Post Load (0.0ms) SQLite3::SQLException: no such table: posts: SELECT * FROM "posts" ActiveRecord::StatementInvalid (SQLite3::SQLException: no such table: posts: SELECT * FROM "posts" ): /app/controllers/posts_controller.rb:5:in `index' Rendered /Users/mike/scratch/blog23/vendor/rails/actionpack/lib/action_controller/templates/rescues/_trace (18.0ms) Rendered /Users/mike/scratch/blog23/vendor/rails/actionpack/lib/action_controller/templates/rescues/_request_and_response (0.6ms) Rendering /Users/mike/scratch/blog23/vendor/rails/actionpack/lib/action_controller/templates/rescues/layout.erb (internal_server_error) Completed in 34ms (DB: 0) | 500 Internal Server Error [http://localhost/posts]
Much nicer. Rails uses a combination of silencers (which just throw away lines matching a particular pattern) and filters (which make regex-based substitutions) to clean up the backtrace.
The guts of the backtrace cleaner are in ActiveSupport::BacktraceCleaner, letting you set up your own cleaners. Most of us, though, will be using the default backtrace cleaner that Rails spins up during initialization, Rails::BacktraceCleaner. Rails adds a variety of filters and silencers “out of the box”:
ERB_METHOD_SIG = /:in `_run_erb_.*/
VENDOR_DIRS = %w( vendor/plugins vendor/gems vendor/rails )
SERVER_DIRS = %w( lib/mongrel bin/mongrel lib/rack )
RAILS_NOISE = %w( script/server )
RUBY_NOISE = %w( rubygems/custom_require benchmark.rb )
ALL_NOISE = VENDOR_DIRS + SERVER_DIRS + RAILS_NOISE + RUBY_NOISE
def initialize
super
add_filter { |line| line.sub(RAILS_ROOT, '') }
add_filter { |line| line.sub(ERB_METHOD_SIG, '') }
add_filter { |line| line.sub('./', '/') } # for tests
add_silencer { |line| ALL_NOISE.any? { |dir| line.include?(dir) } }
end
So, by default, Rails will throw away all the messages from the vendor folders and the servers, among other things. Naturally, you can change these defaults. Rails 2.3 adds a config/initializers/backtrace_silencers.rb file to your application. You can add your own silencers or filters in this file:
Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
You can also tell Rails to remove the default silencers if you’re worried that you have uncovered a deeper bug:
Rails.backtrace_cleaner.remove_silencers!
Because the silencer is set up during the initialization process, you need to restart the server if you make any changes to it.
Currently in edge, the in-browser backtrace pages that you get in development mode show the full backtrace, not the silenced one.
Hopefully I will shake off the post-turkey stupor and write some code today.
Looks like I’m going to roll out at least one and possibly two Rails applications that use delayed_job for asynchronous background job processing. What I haven’t figured out is a good server-side deployment strategy. If you have, I’d love to talk to you.
I’d forgotten how fun trying to pull all the pieces together on a last-minute high-pressure project could be.
I recently hit a situation where I needed to sort an array of ActiveRecord objects on a particular attribute. The catch was that in this case the array started out with the results of a find operation - but then it had a bunch more transient objects added to it that weren’t part of the database. Fortunately the Array#sort method makes short work of this. Given an array a of objects with an entry_date attribute:
a.sort! {|x,y| x.entry_date <=> y.entry_date}
Because this was the only sort I needed on this particular model, I decided to push the operation right down into the model:
class Receipt < ActiveRecord::Base
def <=> (other)
entry_date <=> other.entry_date
end
end
Then the sort is much simpler:
a.sort!
Note that this technique only makes sense if your array isn’t coming straight from the database. If you are retrieving records from the database, you’re better off including an :order clause in your finder to let the database do the sorting.
Too busy to do more than post a couple of links, alas.
This month is definitely ending with a bang.
There are times when I’m glad I’m not a big wheel in the Ruby community. Saves me all sorts of angst, apparently.
There has been an astounding amount of invective and discussion over a recent addition to Rails. Briefly, if you have an array in Rails, you can now use ordinal numbers to get at the first ten members through aliases such as Array#second, Array#third, and so on. Some people are concerned about code bloat, some are concerned about lack of elegance, and DHH’s judgment in writing this bit of code has been seriously challenged.
Well, I’m not happy either - because the changes don’t go far enough. Let’s add one more method to Array and be done with it:
Class Array
def by_ordinal(pos)
self[pos.to_i - 1]
end
end
With this simple addition, you can refer to Array.by_ordinal("3rd"), Array.by_ordinal("21st"), or even Array.by_ordinal("407th"). As a bonus, the naming of the individual members is consistent with Rails’ Inflector#ordinalize method. Please join me in pushing for this to be included in Rails core.
Some days I am amazed that any software at all ever works.
It’s hard to work real effectively when your head is ready to explode. But self-employment doesn’t come with paid sick days.
Things are hopping a bit around here these days, thanks to some short-term work helping out other devs. It’s always fun to come up to speed on a new project.
Here’s a commit message that showed up in the main Rails repository earlier today:
BACKWARDS INCOMPATIBLE: Renamed application.rb to
application_controller.rb and removed all the special casing that was in
place to support the former. You must do this rename in your own
application when you upgrade to this version [DHH]
Well, getting rid of special casing is great, and this commit does indeed simplify some of the Rails internals a bit. But I can hear some of my readers cursing: this seems like an arbitrary change just when Rails 2.2 is about to come out.
Fortunately, if you’re moving to Rails 2.2, this won’t affect you (yet). We’re close enough to 2.2 final that the main repository has been branched: there’s now a 2.2 stable branch (which is currently accepting very few bug fixes) and a master branch that’s targeted at Rails 2.3, or perhaps Rails 3.0. This change - and some other big changes that have been committed over the past few days - is on the master branch.
So, for Rails 2.2, don’t panic. On the other hand, if you’re tracking edge Rails closely, the next few weeks are likely to be a time of vast change (and instability) as some pent-up major changes hit the repository. Be sure you know what you’re cloning before you set up a new Rails application.
Lots of links piled up over the weekend. I’ll try to get something more substantive posted later.
Been having great fun coming up to speed with shoulda the last few days. I think it’s finally starting to make sense to me, though surely there are best practices I’m still missing.
With my latest project past its initial design spike and settling down into more routine stuff, I’m still looking for more to take on, especially into December and beyond.
Even though Rails 2.2 is officially in “release candidate” status, new features are still making their way into the source code tree. While we could debate the suitability of this from a release engineering point of view, some of the new features are certainly sweet. The latest is the addition of the :only and :except options to RESTful routes.
Normally, using map.resources creates routes for all seven of the default actions (index, show, new, create, edit, update, and destroy) for the resource. But in Rails 2.2 (or in the current edge builds), you can fine-tune this behavior. The :only option specifies that only certain routes should be generated:
map.resources :customers, :only => [:index, :show, :destroy]
As with most places in Rails, you can use :except as the opposite of :only:
map.resources :customers, :except => :index
That declaration would give you six of the seven default routes, omitting only a route for the index action.
In addition to an action or an array of actions, you can also supply the special symbols :all or :none to the :only and :except options.
Why do this? In addition to making your code easier to follow, the smaller you can make the routing table, the less memory it will take up - and the less processing time route recognition and generation will take. It can also lower the attack surface of your application by removing unused routes, which is a security win.
If by some chance you missed it, I’m now doing the edge Rails updates for the Riding Rails weblog. Oh, and I’m writing for Ruby Inside and Rails Inside now too. So, you know, I have more outlets for your important news :)
Well, I still have hours to sell, but a couple of little projects appear to be coming together, so hopefully I won’t be on the bench for too long.
You probably already know (well, if you’re a Rails developer) that you can use to_xml or to_json to quickly get XML or JSON representations of Active Record model instances. But did you know that these methods are configurable? By default they simply dump all of the attributes of the model along with their values, but if you want to do something different, you can - and usually without overriding the base methods.
To start, you can specify exactly which attributes to export with the :only or :except options:
@user.to_xml :only => [ :name, :phone ] @user.to_xml :except => :password @user.to_json :only => [ :name, :phone ] @user.to_json :except => :password
You can include associated records, nesting as needed, with the :include option:
@user.to_xml :include => {:orders =>
{ :include => [:shipments, :backorders] }}
@user.to_json {:orders =>
{ :include => [:shipments, :backorders] }}
:only and :except also work on includes:
@user.to_xml :include => {:orders =>
{ :include => [:shipments, :backorders] },
:only => :order_date }
@user.to_json {:orders =>
{ :include => [:shipments, :backorders] },
:only => :order_date }
You can create XML or JSON attributes from model methods by using the :methods option:
@user.to_xml :methods => :permalink @user.to_json :methods => :permalink
Additionally, there are some options that apply only to to_xml. :skip_instruct suppresses the XML processing instruction. :skip_types suppresses the output of types to the XML. :dasherize => false turns off dasherization of column names.
I’ve shut down and reformatted my Windows desktop for good (I hadn’t turned it on for six months or so, it just took me this long to get around to reformatting the drives). If anyone wants a deal on a Dell PowerEdge 1800 server before I EBay it, holler.
If you take a look at the Rails source code, you’ll find numerous useful comments like this one from ActionController::Base:
# All requests are considered local by default, so everyone # will be exposed to detailed debugging screens on errors. # When the application is ready to go public, this should be set to # false, and the protected method <tt>local_request?</tt> # should instead be implemented in the controller to determine # when debugging screens should be shown. @@consider_all_requests_local = true cattr_accessor :consider_all_requests_local
But if you check your favorite Rails API site for documentation of consider_all_requests_local, you’ll come up blank. What’s up?
I spent some time chasing this, and it turns out to be a conflict between the way that Rails is commented and the way that rdoc thinks things should be done. There’s actually a ticket in the old Rails Trac with a proposed resolution for this. As it happens, that ticket isn’t quite right, but it provoked rdoc into changing things. The secret lies in the rdoc 2.x support for documenting metaprogrammed methods.
To properly document cattr_accessor (and similar) declarations in your own Rails code, you need to do two things. First, upgrade from your musty old rdoc 1.0.1 to a more recent version - 2.2.1 is current. If you look at their downloads you will find there is a gem version, but just installing this may not be enough: putting the gem on my system gave me rdoc 2 from the command line but rdoc 1 from rake tasks. That’s because (at least on my Mac), rdoc is also out there in the ruby/1.8 standard tree, and so I had to replace the 1.0.1 there with the new bits.
Second, you need to change your markup comments to tell rdoc that this is a metaprogrammed method. Here’s the revision for that method from ActiveController::Base:
@@consider_all_requests_local = true ## # :singleton-method: # All requests are considered local by default, so everyone # will be exposed to detailed debugging screens on errors. # When the application is ready to go public, this should be set to # false, and the protected method <tt>local_request?</tt> # should instead be implemented in the controller to determine # when debugging screens should be shown. cattr_accessor :consider_all_requests_local
The ## indicator tells rdoc that this is a metaprogrammed method, which means it will ignore the first token on the declaration and pick up the second one as the method name. The # :singleton-method# indicator tells rdoc to document this as a class method rather than as an instance method.
The Rails Documentation team is exploring how we’ll fix up the core Rails source to use the new markers. Meanwhile, you should start using this anywhere that you have the cattr methods in your own code or plugins - and upgrade your rdoc bits in anticipation.
Yesterday saw my first posting to the official Rails weblog. A nice step on the way to world domination, I guess.
In Rails 2.2, if you include a belongs_to or references column in a call to the model generator, it will automatically add the belongs_to declaration to the model, as well as creating the foreign key column in the migration.
For example, run this from the command line:
script/generate model order order_date:datetime customer:belongs_to
And you’ll find that the generated Order model looks like this:
class Order < ActiveRecord::Base belongs_to :customer end
Nothing earthshaking, but it will save you a few keystrokes.
Personally, I think we ought to explore the possibilities of making the model generator much more full-featured. I don’t see any reason why it couldn’t build validations, associations, and accessibility declarations at generation time. As a first step on this road, I’ve submitted a Rails patch. If you like the idea (and you’ve got a copy of edge hanging around), go give it a try and let me know what you think.
I tossed out a few more bits of open source code over the weekend: a fork of suprails (though actually I hope the original project just merges my one tiny change), and a proposed change for Rails core (which you’re welcome to go test and, hopefully, +1).
Maybe it’s just me and the amount of support and writing I’m doing these days, but I find myself fairly frequently looking at a bit of core Rails code and wondering “what that in release X”? To help figure that out, here’s a list of Rails version release dates (starting with 1.0) pulled together from the svn and git repos:
12/13/05 1.0.0 3/22/06 1.1.0 RC1 3/28/06 1.1.0 4/06/06 1.1.1 4/09/06 1.1.2 6/28/06 1.1.3 6/30/06 1.1.4 8/09/06 1.1.5 8/10/06 1.1.6 11/23/06 1.2.0 RC1 1/05/07 1.2.0 RC2 1/18/07 1.2.0 1/18/07 1.2.1 2/06/07 1.2.2 3/14/07 1.2.3 10/05/07 1.2.4 10/12/07 1.2.5 11/24/07 1.2.6 9/30/07 2.0.0 PR (Preview Release) 11/09/07 2.0.0 RC1 11/29/07 2.0.0 RC2 12/07/07 2.0.0 12/07/07 2.0.1 (2.0 final) 12/16/07 2.0.2 5/11/08 2.0.3 9/04/08 2.0.4 10/19/08 2.0.5 5/11/08 2.1.0 RC1 5/31/08 2.1.0 9/04/08 2.1.1 10/23/08 2.1.2 10/24/08 2.2.0 (2.2 RC1) 11/14/08 2.2.1 (2.2 RC2)

