Tag Archives: Ruby

ActiveRecord strict mode

I really like ruby and rails, but I find it frustrating as a lone developer.

The main path for Ruby / Rails seems to be very well documented. However, the second I get off the main path, which it seems everyone must do, especially someone who is upgrading an app that started as a rails 2.1.0 application, the documentation is scarce. I find I wind up having to search in source code more often than not to understand what’s going on. And that’s scary.

Case in point, I recently upgraded from rails 3.2 to rails 4.0. They implemented a major change with ActiveRecords that I can find no mention of any where except in the source and change log.

* `mysql` and `mysql2` connections will set `SQL_MODE=STRICT_ALL_TABLES` by
default to avoid silent data loss. This can be disabled by specifying
`strict: false` in your `database.yml`.

This is a good thing. For years i have been silently losing data. Data I don’t care about, but still, since it’s silently loss, I didn’t know.

However, after upgrading the app, fixing all the deprecation warnings, and ensuring all my test passed, I pushed the code to production. Then I started getting errors like:

An ActiveRecord::StatementInvalid occurred in items#search:

Mysql2::Error: Data too long for column ‘name’ at row 1…. (with lots of boring mysql)

Basically, my name field, at 256 characters was not long enough for some data. The error message made it clear what was happening, but I didn’t understand why they would make this type of change, without documenting it in the migration documents. Maybe they could have gone through a deprecation phase where it warned you first, before going from silent to exception?

It wasn’t until after I had fixed my code to either have the proper field lengths, or manually truncate the data myself that I found that a simple “strict: false” in my database.yml file would have returned to the old behavior while I tracked down the problem, or properly checked for it, so I wouldn’t get a server error.

Another more deadly example, one that took me over a month to track down was back in rails 3.1 when they changed the meanings of .dup and .clone.

ActiveRecord::Base#dup and ActiveRecord::Base#clone semantics have changed to closer match normal Ruby dup and clone semantics.
What this really meant to me was, everywhere I was using .clone, I needed to change to .dup. I was having object rot because when It thought I was cloning an item to make a new one, I was changing the original. I needed to .dup it, so I would not copy the id at the time of duplication. Basically, for what I needed, .dup and .clone changed names. This happened silently without warning or being highlighted in the upgrade documentation.

factory_girl_rails and ruby 1.8.7

factory_girl_rails gem requires factory_girl gem, which starting at 3.0.0 requires ruby 1.9.2. The Last factory_girl_rails version that works with ruby 1.8.7 is 1.7.0, which uses factory_girl 2.6.4

In Gemfile:

gem 'factory_girl_rails', '~> 1.7.0'

ActiveRecord object caching in Ruby on Rails

Yesterday I started playing with basic caching for PriceChirp and tried what I thought would be easy. Boy was I wrong. It turns out what I was attempting to do is not supported by :memory_store in the development environment. Before moving to :mem_cache_store, I was able to find a work around. The work around is outlined below for those who do not have the option of using memcached. However, if you can use memcached, it is by far the better route to take.

My goal was to cut down on the number of database hit by caching the resultant ActiveRecord object in :memory_store.


#models/foo.rb
 def self.cool_widget
 Rails.cache.fetch('cache_object_name') { find_by_name('cool_widget') }
 end

#config/environments/development
 config.action_controller.perform_caching = true
 config.cache_store = :memory_store

#controler/foos_controllers.rb
 awesome_widget = foo.cool_widget
 logger.info awesome_widget.id

In script/console and in rails production, this works as you would expect. However, in the rails development environment, funny things happen. On the first page view, all looks good. On the second page view, as rails attempts to pull the object out of cache, rails cashes with the following error:

 .../activerecord/lib/active_record/attribute_methods.rb:142:in `create_time_zone_conversion_attribute?'
 

A google search lead me to:

https://rails.lighthouseapp.com/projects/8994/tickets/1290-activerecord-raises-randomly-apparently-a-timezone-issue

Here they talk known problems about caching Active Record objects on development servers. Something about the way the object are torn down between page loads to allow for every hit to get a new instance of the controller.

At the very end of the discussion (over the course of a year), I got the following work around:

http://gist.github.com/251886


# put this in lib/nil_store.rb:
 class NilStore < ActiveSupport::Cache::Store
 def initialize(location='//myloc'); end
 def read(name, options = nil); super; end
 def write(name, value, options = nil); super; end
 def delete(name, options = nil); super; end
 def delete_matched(matcher, options = nil); super; end
 end

# and then in environments/development.rb:

require 'nil_store'
 config.cache_store = NilStore.new

# or you could just turn on development class caching:

config.cache_classes = true

This “nil_store” routine basically prevent caching in the development environment which makes everything work. On production, I did not notice any problems.

Other work arounds to this bug include, not caching the ActiveRecord object or using a different caching routine, like memcached.

Number to Currency Outside Rails

I created a module I am also using both in rails and for some batch processing outside of rails. In order to ensure my data was formatted the same with both environments, I needed to figure out how to get access to the active_view helper number_to_currency outside of rails. Here is how I did it:

require 'rubygems'
require 'action_view'

def number_to_currency(number, options = {})
  ActionView::Base.new.number_to_currency(number, options)
end

Rescuing from open-uri timeouts

Found an issue with open-uri because today Amazon’s API is wonky. The same issue will occur when accessing any remote data via open-uri (like a RSS feed) if the data source is going to slow. The relevant part of my ruby code looks like:

  begin
    doc = Nokogiri(open(api_url))
  rescue
    print "Connection failed: #{$!}\n"
    next
  end

For some reason, the rescue does not catch a timeout error.

/usr/lib64/ruby/1.8/timeout.rb:54:in `rbuf_fill': execution expired (Timeout::Error)

Explicitly catching the timeout error fixes the code.

  begin
    doc = Nokogiri(open(api_url))
  rescue Timeout::Error
    print "Timeout::Error: #{$!}\n"
    next
  rescue
    print "Connection failed: #{$!}\n"
    next
  end

Good to know, as you never know when your remote data provider will be slow.