Sometimes you want to raise an exception when a method fails but without losing information about an inner exception. Let me explain it with an example.
At Watu we have a method that causes a user to be indexed in our search engine. This method is called many times in different situations. One of those situations is when indexing most or all of our users. Recently, something failed and I got this exception:
undefined method `each' for #<String:0x10dab8fc>
Something that should be an array is actually a string. In this case the indexing method is correct, it’s just getting broken data. I want to fix the bug in the data generation, but to locate it, I need to know which user has broken data. I added a rescue clause to my indexing method to show me that data:
def index
# ...
rescue
raise "Error when indexing user #{self}"
end
Now I get something like:
Error when indexing user #<User:1234>
which allows me know that user 1234 has something wrong in its data. The problem is that now I have no idea what the issue is. I lost the information about trying to call each on a string.
The solution to this problem is exception wrapping (or nesting). You want the custom exception to wrap the other one so that you have both pieces of information. This, for example, exists in Java and if you search the web you’ll find ways on how to implement it in Ruby. Implementing this manually is not needed anymore since Ruby 2.1. Unfortunately, it’s a bit hidden and the tools haven’t caught up yet.
The secret lies in a new method in the class Exception called, cause. At the time of this writing it doesn’t even have documentation:
No documentation for the method Exception#cause
Using it is very straightforward. Just raise an exception in the rescue clause and the new exception will have the previous one as its cause. For example, in this case:
begin
a = 1 / 0
rescue
raise "Something went wrong"
end
you get two exceptions: the divided-by-zero wrapped inside one with the “Something went wrong” message.
The problem arrises that nobody seems to be using the causes of exceptions yet. If you run that in IRB, this is what you get:
RuntimeError: Something went wrong
from (irb):4:in `rescue in irb_binding'
from (irb):1
from /Users/pupeno/.rvm/rubies/ruby-2.1.0/bin/irb:11:in `<main>`
But the exception’s cause is in there… hidden. If you catch the outer exception you can access its cause. For example:
begin
begin
a = 1 / 0
rescue
raise "Something went wrong"
end
rescue => e
puts e
puts e.cause
end
would produce:
Something went wrong
divided by 0
The reason why it doesn’t produce something like that by default is because whatever IRB is using to print exceptions is ignoring the exception’s cause. Now we’ll have to wait until all the tools catch up with this new feature.
Well, we don’t actually have to wait. Aside from the fact that most of them are open source and you can fix them yourself, Ruby allows you to monkey patch so you can fix your own copy of these tools.
In my case I needed rake to print inner exceptions, so I wrote this monkey patch (which works for rake 10.1.1):
module Rake
class Application
def display_error_message(ex)
trace "#{name} aborted!"
display_exception(ex)
trace "Tasks: #{ex.chain}" if has_chain?(ex)
trace "(See full trace by running task with --trace)" unless options.backtrace
end
private
def display_exception(ex, margin = "")
trace "#{margin}#{ex.message}"
if options.backtrace
trace "#{margin}#{ex.backtrace.join("\n#{margin}")}"
else
trace "#{margin}#{Backtrace.collapse(ex.backtrace).join("\n#{margin}")}"
end
if ex.respond_to?(:cause) && !ex.cause.nil? # Ruby < 2.1.0 doesn't have *cause*
trace "#{margin}which was caused by:"
display_exception(ex.cause, "#{margin} ")
end
end
end
end
This is something that I would like to see in rake itself so I created an issue request (#253). Take a look at it to follow the development of this feature and hopefully, all tools will start displaying causes in one way or another.
Most applications, web, desktop or mobile, handle some kind of data. When we are developing them we generally generate some sample data to play with and we forget to ever run the application without it. The problem is that the first impression people will get of our app is without data. And first impressions are important.
In the application I’m building, Watu, we are resorting to just create some sample data for customers to play with. Making the application beautiful and meaningful without data is just too hard. It seems the guys at JetBrains spent some time thinking of this because RubyMine 4.0 shows this when there are no open files:
I think that simple change it’s a good step towards making the application nicer in the no-data scenario, making people happier, as well as making people more productive in it, making the application more useful.
I do wonder why they didn’t include the most useful of the shortcuts: ⌘⇧N. I think I press that more than any other. It pops up this little dialog:
in which you can type and it’ll search among all your files (and files inside the gems, that is, libraries, of your project if it doesn’t match anything in your project or if you enable by ticking the include non-project files):
What I really like, compared to other implementations of this feature, is that you can add more parts of the path, for example:
Without that feature, my productivity would drop a 10%. I’m not exaggerating, that’s my estimation, as I recently have to code using TextMate instead of RubyMine.
Before you send me the hate-mail, I know TextMate has a similar feature although I think not as advanced (not without plugins at least) but since the key shortcut was different, it was almost like it didn’t exist for me, so I experienced coding without that feature at all.
Another potentially useful way to find code is to use ⌘N which allows you to search for a class:
But since in a Rails projects most classes are in a file with the same name (but underscore instead of camel case) and the file dialog allows me to find views, wich the class dialog doesn’t, I never use the class dialog.
No… I’m not affiliated with JetBrains, makers of RubyMine in any way. I just love the tool and I wish more Ruby programmers would give it a try because I think they’ll also find it useful and the more people that are using it, the more resources JetBrains is likely to put into its development which ultimately benefits me. And they are cool guys, a pleasure to deal with every time I report a bug or ask for a feature.
I find myself needing to have the full URLs in Rails’ logs. Normally you get something like:
[sourcecode lang=”text”]
Started GET "/" for 127.0.0.1 at 2011-08-27 13:13:10 +0200
[/sourcecode]
but I needed
[sourcecode lang=”text”]
Started GET "http://foo.bar:3000/" for 127.0.0.1 at 2011-08-27 13:13:10 +0200
[/sourcecode]
because the app does different things depending on the domain and when it fails, I have to know which URL was hit. The solution I ended up with was adding this in an initializer:
[sourcecode lang=”ruby”]
class Rails::Rack::Logger << ActiveSupport::LogSubscriber
protected
def before_dispatch(env)
request = ActionDispatch::Request.new(env)
info "\n\nStarted #{request.request_method} \"#{request.url}\" for #{request.ip} at #{Time.now.to_default_s}"
end
end
[/sourcecode]
That’s monkey-patching Rails’ own logger. Credit for the solution goes to numbers1311407.
My question for the people using Rails, do you think having a configurable logger in Rails would be useful or nice? If so, I could make a patch for Rails but I have made patches before that failed to gather the needed popularity and thus were ignored. I’m not wasting my time like that again.
A recent update to RubyGems is causing a lot of deprecation warnings like these:
[sourcecode]
NOTE: Gem::Specification#default_executable= is deprecated with no replacement. It will be removed on or after 2011-10-01.
Gem::Specification#default_executable= called from /usr/lib/ruby/gems/1.8/specifications/rubygems-update-1.4.1.gemspec:11.
NOTE: Gem::Specification#default_executable= is deprecated with no replacement. It will be removed on or after 2011-10-01.
Gem::Specification#default_executable= called from /usr/lib/ruby/gems/1.8/specifications/bundler-1.0.7.gemspec:10.
NOTE: Gem::Specification#default_executable= is deprecated with no replacement. It will be removed on or after 2011-10-01.
Gem::Specification#default_executable= called from /usr/lib/ruby/gems/1.8/specifications/file-tail-1.0.5.gemspec:10.
[/sourcecode]
I generally like software to move forward and the way to do that is deprecate and then after a while, make backwards incompatible changes. It’s painful but there’s no other way.
I do have a problem with all the cron jobs of my web apps like Keep on Posting or DNSk9 flooding my inbox with those warnings. Thankfully, that’s not hard to fix. Where I was doing:
When you are building systems like my Keep on Posting or my DNSk9 that send emails there’s always the danger that you’ll accidentally fire emails from your development machine to real users. You really don’t want to do that because it’s annoying and extremely unprofessional.
It happened to me a couple of times. Thankfully, nothing serious. But I learned the lesson. That’s why in my user models now I have a safe_email method which I use instead of accessing email whenever I’m about to actually deliver a message.
The method safe_email ensures that nobody will receive a message unless I’m in production and at the same time it’s good for testing. Obviously most of the time in development and testing mode I don’t deliver emails at all, but sometimes, I make an exception:
def safe_email
if Rails.env.production? || email.blank? # If the email is blank (or nil), let it be.
email
else
"pupeno+#{email.gsub("@", "_AT_")}@pupeno.com"
end
end
When I need to run something periodically on production, I always implement it as a rake tasks and install it as a cron job. Nevertheless there’s some setup to do in the task to have proper logging and error reporting.
This is the template I use for creating those tasks:
namespace :projectx do
desc "Do something"
task :something => :environment do
if Rails.env.development?
# Log to stdout.
logger = Logger.new(STDOUT)
logger.level = Logger::INFO # DEBUG to see queries
ActiveRecord::Base.logger = logger
ActionMailer::Base.logger = logger
ActionController::Base.logger = logger
else
logger = ActiveRecord::Base.logger
end
begin
logger.info "Doing something"
rescue Exception => e
HoptoadNotifier.notify(e)
raise e
end
end
end
While in development mode, it outputs to the console for convenience.
For a personal project I’m working on, I need to find out the smallest time period with more than 5 records. I essentially wrote this code:
period = [1.week, 1.month, 1.year].select_first do |period|
Record.where("published_at >= ?", period.ago).count >= 5
end
only to find out that the select_first method doesn’t exist. So I wrote it:
module Enumerable
def select_first(&predicate)
self.each do |item|
if yield(item)
return item
end
end
return nil
end
end
and then of course, I tested it:
require "test_helper"
require "enumerable_extensions"
class EnumerableTest 2 }
end
should "select_first the first one" do
assert_equal 1, [1, 2, 3, 4].select_first { |i| i >= 1 }
end
should "select_first the last one" do
assert_equal 4, [1, 2, 3, 4].select_first { |i| i >= 4 }
end
should "select_first none" do
assert_equal nil, [1, 2, 3, 4].select_first { |i| i >= 100 }
end
end
I’ve just released another gem, this one extends Hash to contain another method called hmap. This solves a problem I face ofter: how to run a map in a hash that returns another hash, for example:
Ruby doesn’t have enums and in Rails I sometimes need it. I’ve come out with my own way of doing after some trial and error. First I want to be able to access these enums as constants in a class, like:
class Pizza
RAW = 1
COOKED = 2
BOXED = 3
DELIVERED = 4
EATEN = 5
end
If I’m storing those values on the database, I’d like to have my database be more readable, so, I just store strings:
class Pizza
RAW = "raw"
COOKED = "cooked"
BOXED = "boxed"
DELIVERED = "delivered"
EATEN = "eaten"
end
That’s not very efficient and there are better ways these days. But it’s simple and premature optimization is the root of all evil. Anyway, back to Ruby, I’d like to be able to get a list of all possible enum values, to be able to populate selections for example:
class Pizza
RAW = "raw"
COOKED = "cooked"
BOXED = "boxed"
DELIVERED = "delivered"
EATEN = "eaten"
STATES = [RAW, COOKED, BOXED, DELIVERED, EATEN]
end
Simple enough except that it doesn’t follow DRY style. In Ruby we can do better:
class Pizza
STATES = [
RAW = "raw",
COOKED = "cooked",
BOXED = "boxed",
DELIVERED = "delivered",
EATEN = "eaten"
]
end
That defines the constant and since the result of RAW = "raw" is "raw" we can also add it to an array at the same time.
John, the manager of the Ruby Pizza Shop was concerned that some pizzas were devoured immediately and others took as long as 15 minutes. Decided to improve his business he started investigating the whole procedure and he noticed that as soon as the pizza left the kitchen, some cooks considered delivered and marked them as such. That was wrong so instead of doing a pizza-state training, he decided we should improve the UI. Let’s describe the state.
class Pizza
STATES = [
RAW = "raw",
COOKED = "cooked",
BOXED = "boxed",
DELIVERED = "delivered",
EATEN = "eaten"
]
STATE_EXPLANATIONS {
RAW => "The pizza is not a pizza yet, just a bunch of ingredients.",
COOKED => "OMG! That smells good!",
BOXED => "It's ready to go.",
DELIVERED => "The pizza has been snatched out of the hands of a delivery boy.",
EATEN => "The pizza is no more."
}
end
Of course we can do better than that and merge it in one:
class Pizza
STATE {
(RAW = "raw") => "The pizza is not a pizza yet, just a bunch of ingredients.",
(COOKED = "cooked") => "OMG! That smells good!",
(BOXED = "boxed") => "It's ready to go.",
(DELIVERED = "delivery") => "The pizza has been snatched out of the hands of a delivery boy.",
(EATEN = "eaten") => "The pizza is no more."
}
end
Stylistically I’m not a fan, but semantically, that’s dryer. Now, we can get the list of states like this: