Decimating deprecated finders

I imagine that while planning the release of Rails 5, and considering the prospect of maintaining the activerecord-deprecated_finders gem, the rails team had the following to say:

Nope!*

The impact being that every sad soul who put off replacing old style finder syntax, like

Post.find(:all, conditions: { published_on: 2.weeks.ago }, limit: 5 ...)

or any dynamic finders,

find_all_by_...
find_last_by_...
scoped_by_...
find_or_initialize_by_...
find_or_create_by_...

with the new syntax,

Post.where(published_on: 2.weeks.ago).limit(5)
Post.find_all_by(author: 'Shakespeare', ...)

was/is in a bit of a pickle.

Maybe this was easy for you, maybe you proactively began this process long before the Rails 5 release (you know… to be ready).

But maybe, just maybe, Rails upgrades slid down into the dark basement beneath your house of Important Things To Do™ and remained there, glaring silently at you from the abyss, waiting. I’ve recently had the pleasure of descending into such dungeons, and I’m here to tell you there is hope!

I’m speaking to you, yes you.

I’ve found something that might help you slay this brooding beast. A Sword of Glamification (Level 29)…

Synvert

Befriend your “boo” in the basement and give it the glow-up it’s always deserved. Make it clean, updated, secure, and a friend of developers everywhere.

Just sprinkle a few synvert snippets onto its weary code-bones.

# Handles find with hash options
$ synvert -r rails/convert_models_2_3_to_3_0

# Handles dynamic finders
$ synvert -r rails/convert_dynamic_finders

and, by the magic of AST tree parsing, deprecated finders melt into beautiful chains of method invocations.

Obviously this won’t solve all your upgrade woes, but it’s a good place to start. The changes made should be well reviewed. There are still some edge cases where the modifications don’t produce the desired change. And, as always, it is highly valuable (one might also say indispensable) to have a solid test suite with good coverage to ensure app logic still meets expectations.

There are other snippets for rewriting ruby/rails code, so check those out. Maybe one of them solves something you’ve been dreading for a long time.

Parser

If you are interested in learning about parsing and rewriting ruby code, check out Parser, the gem that Synvert depend on to accomplish their ruby-rewriting functionality. It provides a way to create your own rewriters.

How’d you find this… glad you asked

At this point, the important information has been shared. However, if you want to hear about a solid yak-shave… Read on.

Shockingly, I didn’t find this tool via usual search-foo like "remove rails deprecated finders". Actually, I accidentally found the rails snippets while searching for a library for parsing ruby.

But to get to that point…

  1. Automation!
  2. Starts writing tediously crafted regex in sed calls
  3. Spends considerable time on this…

    Wait, the hash condition arguments could appear in any order and the method call could span multiple lines…

  4. Dies a bit inside

  5. Quits development and moves to Tibet to study the secrets of an attachment free life

  6. During final months of training must traverse a mountain pass to yak lair and retrieve a golden hair

  7. Shaves a yak

  8. Returns with yak hair to teacher

    Me: Have I succeeded in my training master?
    Master: You lack only one final thing
    Me: What is that?
    Master: You must finish what you began
    Me: It is impossible, no Regex can handle the task
    Master: Look into the code, and see it looks out at you, parse the secrets of the Ruby
    Me: Of course! A parser!

  9. Searches internet for ruby parsing lib, finding Parser, which links to an article about its DSL for rewriting ruby code

    Wonder if someone has created libraries that use this functionality?

  10. Searches for other gems that depend on it, which leads to Synvert

  11. Starts attempting to write a Synvert::Rewriter to change deprecated finders (and actually gets pretty far pretty quickly)

  12. Sees link on website to synvert snippets and realizes that directory contains snippets for rewriting ruby code for rails upgrades

🤦 So yeah, that’s how it went down.

Footnotes

*: Not an actual quote from the rails team