The following code is not thread-safe (in Ruby 1.8):
def quote_string(s)
self.class.instance_eval do
define_method(:quote_string) do |s|
sleep 0.1
s
end
end
quote_string(s)
end
The reason is block argument s is bound to method’s argument. When new method is called all threads share the same variable, so if you call this method in several threads, it wouldn’t return argument anymore.
Test script is here. When it’s run, it outputs
ruby 1.8.8dev (2009-09-14) [i386-darwin10.0.0]
1 fail [“another test”, “another test”]
2 fail [“another test”, “test”]
ActiveRecord has the following code
# Quotes strings for use in SQL input in the postgres driver for better performance.
def quote_string(original_value) #:nodoc:
if @connection.respond_to?(:escape)
self.class.instance_eval do
define_method(:quote_string) do |s|
@connection.escape(s)
end
end
elsif PGconn.respond_to?(:escape)
self.class.instance_eval do
define_method(:quote_string) do |s|
PGconn.escape(s)
end
end
else
# There are some incorrectly compiled postgres drivers out there
# that don’t define PGconn.escape.
self.class.instance_eval do
remove_method(:quote_string)
end
end
quote_string(original_value)
end
So if you use ActiveRecord with postgres and ruby 1.8, make sure do not use threads ;-)