Gotchas While Migrating from Rails 3.2 to 4.0

There are good resources to help you with an upgrade from Rails 3.2 to 4.0 — here are a few gotchas that I noted during our upgrade!

SQL_MODE=STRICT_ALL_TABLES

This lesser-known change was definitely an improvement, but it can really bite you. Previously, Rails <= v3.2 out-of-the-box would not set MySQL to strict mode. Meaning, for instance, that values that exceeded your column’s VARCHAR limit would just get truncated. Now in strict mode, MySQL will throw an error and reject the value. 

ActionController::UnknownFormat

Controllers will now raise this error instead of directly returning a 406, and they won’t be rescued by default in your controller tests. references(:model)You’ll notice this if you see the deprecation messages, but whenever you add includes(:model) to an ActiveRelation scope, and then later reference it in a condition, you need to specify references(:model) in the scope as well.

ActiveRecord::Relation

This will no longer be the class that is returned with your scopes. If your class is calledMyClass, for instance, you’ll get back an instance ofActiveRecord::Relation::ActiveRecord_Relation_MyClass (which would still inherit from ActiveRecord::Relatio.

MyModel.all

The all method used to load the records from your scope. In 4.0, it’s a scope in itself (and MyModel.load should be used to explicitly load the records now).

MyModel.first[‘not_an_attribute’] = ‘foo’

Previously you could treat AR instances like arbitrary hashes, and store any value you wanted. Now, those keys must be real attributes (eg columns) on the model.

ActionView’s truncate()

This method previously returned non-html_safe strings. Now it returns auto-escaped strings that are marked as html_safe. This will break the :omission option if you don’t want it escaped (like rendering a "Click to show more" link, but you can pass a block instead to render the unescaped omission.

Timestamps in JSON 

When encoding something into JSON, Rails will now include millisecond-precision in timestamps. It’s not a well-documented change, but it bit us in a case where ElasticSearch couldn’t parse timestamps with milliseconds. I believe Rails 4.1 adds an option to configure this.

rake db:structure:dump

The MySQL implementation of this rake task had all of its own code for dumping the database structure, while other adapters used the native tools. Rails 4 will now use mysqladmin to dump the structure. This probably only affects you if you had monkeypatched the old dumper code.

try()

Previously, the try method would raise a  NoMethodError if you called a method that the receiver didn’t have. In Rails 4, try will call respond_to? on the receiver and return nil if that returns false. So you.try(:can).try(:chaining).try(:anything).try(:together).try(:now). This was a little controversial around these parts — double check your try usage before you upgrade!

Other Deprecations

* find(:first)

* update_all(..., {my: CONDITIONS}) (when called with a conditions hash)

* :confirm option in ActionView. Use data: {confirm: "test"} with UJS instead.

* ActiveRelation#last when called with finder options

* ActiveRelation#sum when called with a block

* whiny_nils option is gone

Sending Batch emails over Mailgun SMTP with ActionMailer

Recently I was checking out Mailgun's api and wanted to try batch emails over their SMTP api.

I tried it with Rails 3 ActionMailer, although it’s not very straight-forward to do, and there’s not much info around about this combination (besides this gem). If you have the same issue, try this!

Migrating from Jammit to the Asset Pipeline: Cross-check Your Expanded Bundle Paths

Switching a Rails app from Jammit to Asset Pipeline can involve a lot of work, but one of the most important pieces is ensuring you’re including the same files in the same order.

If you want to quickly cross-check that each asset bundle will include the same list of paths, try this:

Leap + Ruby

I really wanted to use the Leap SDK in Ruby after I recently got my Developer Kit.

I tried writing an FFI lib (to support all Ruby versions) but noticed it might not be sufficient.

Then I tried writing a C-extension, but realized I don’t have enough time for that right now.

Finally I tried writing a wrapper with JRuby instead (the Leap SDK includes Java libs) and it was so simple.

Pretty excited to do more with this library. Many thanks to Leap and JRuby!

https://github.com/tiegz/LeapRuby

I recently reprogrammed the MaKeyMaKey to control Roy the Robot’s hand, which just meant turning 6 of the input pins on MaKeyMaKey into 6 output pins, and using the Arduino Servo library to control them (my fork of the firmware is here).

I also heard about a MaKeyMaKey contest on UncommonGoods & put together this video to demo the hand.

Unfortunately, the servos weren’t strong enough to play the piano :(

Hidden Secrets of the Rails Dev: Gotchas while Migrating from 1.8 to 1.9

There are quite a few good articles on the web about changes in Ruby 1.9. 

Here are just a few changes that tripped me up a bit while making the upgrade in a Rails app:

  • String#each has been removed: use String#each_line instead
  • String#to_a was removed: use .lines.to_a instead
  • "Some string" + Exception.new("hey that's bad") throws a TypeError now: force the exception using to_s
  • [1,2,3].to_s now returns "[1,2,3]" instead of "123": ie, now it’s inspect instead of join
  • incompatible encoding regexp match (ASCII-8BIT regexp with UTF-8 string): specify utf8 encoding with switch: /blah/ -> /blah/u, or Regexp.new("blah", Regexp::FIXEDENCODING). Read more about 1.9 and encoding at Shades of Gray 
  • 1.9.2+ doesn’t include “.” in the path ($:) anymore: use the new require_relative, or if you need to just add it explicitly: $: << "." if RUBY_VERSION =~ /1\.9/
  • 1.9 is less forgiving for spaces before args now: instead of getting a warning for the space in link_to ("home", "/"), 1.9 will now throw an error
  • 1.9 changed Method introspection: instead of method(:to_s).__file__ and method(:to_s).__line__, use method(:to_s).source_location instead
  • 1.9.3 adds new YAML parser: basically this breaks any serialized rows you might have saved in 1.9 (with Syck) with Rails’ serialization attributes. Solution here.
  • 1.9 changes Date#parse format from “MM/DD/YYY” to “DD/MM/YYYY”: this cascades to Rails’ DateTime#parse

Also, try this String monkey patch if you’re transitioning between 1.8 and 1.9. Call this whenever you need to ensure a string is utf8:

Dreams of ARel: Visualize your ActiveRecord queries

I’m currently trying to track down an ActiveRecord 3.2.* bug related to generating a count query, and thought it might be useful see a visualization of the ARel object that this query generates.

It turns out this is pretty easy!

ARel already implements a method called “to_dot” that converts your ARel into DOT, which is readable by Graphviz.

Building an API: Rails 3 vs Grape

I’ve been pretty impressed with the Grape Rack library for building an API, but I was curious how it stacks up against Rails 3, now that Rails has been Rack-ified and has steadily become more hospitable to APIs.

Using an existing Rails app with a Grape API mounted as middleware, I ran a benchmark against a vanilla API with this environment:

  • Grape 0.1.5
  • Rails 3.0.10
  • Passenger 3.0.5
  • Ruby Enterprise Edition (ruby 1.8.7), patchlevel 334
  • Macbook Pro, 2.4 GHz / 8GB, OS X 10.6.8

And it looks like Grape wins in this particular environment:

  • Grape averages 47.21 req/sec
  • Rails 3 averages 31.41  req/sec

Grape vs Rails 3 API performance

Here’s how I implemented both scenarios:

Hidden Secrets of the Rails Dev: Gotchas While Migrating from 2 to 3

Upon migrating from Rails 2 to 3, one might happen across some “gotchas”. I present a few such that you may heed caution.

ActiveSupport::Callbacks#run_callbacks

This method takes a &block parameter. In Rails 2, &block will run after each callback, and halt the chain if it returns false. In Rails 3, &block will run after the :before/:around callbacks and before the :after callbacks. More has changed about callbacks, so please read the docs.

Mail#header

ActionMailer in Rails 3 uses a different underlying library than 2: mail instead of tmail. Setting headers in the new library will accumulate headers rather than replacing them:

m['X-Something'] = 1
m['X-Something'] = 2
m.header['X-Something'] = 3

Now m has 3 values for the X-Something header: 1, 2 and 3.

ActiveRecord::Base#touch

In Rails 2, touch() ultimately calls save!() and runs through all the validation and callbacks. In Rails 3, touch() saves the record using update_all(), so no validations are performed and only the new after_touch() callback is run.

ActiveRecord#order

In Rails 2, queries are ordered like this:

User.first(:order => "name")

In Rails 3, AREL gives us a new method for queries called order(), but remember that it will accumulate order values instead of replacing them:

User.order("name").order("id").first
# ... ORDER BY name, id .... #

Remember to use reorder() to reset the value:

User.order("name").reorder("id")
# ... ORDER BY id ... #

Reorder your Authlogic persistence callbacks

One thing lacking from ActiveSupport::Callbacks, imo, is a way to reorder callbacks.

For instance, it would be nice if you could define the order in which Authlogic (which uses ActiveSupport::Callbacks) tries to persist a session (ie ‘remember’ cookie, then ‘session’ cookie, then ‘http_auth’, and so on).

Here’s some code to put at the end of your session models to prioritize their callback chains…

For Rails 2:

For Rails 3:

(link)

Accent theme by Handsome Code


view archive



Ask me anything