The RailsNotes Newsletter 🟥 ISSUE #17

🟥 ISSUE #17 (enums, value objects, a field guide, and sorting with #in_order_of)

How it feels when your enum column perfectly represents the states you need it to 🧘 ♦️ ♦️ ♦️ ♦️ 

— SPONSOR —

Efficient Search in Rails with Postgres — Speed up a search query from seconds to milliseconds and learn about exact matches, similarity matches with trigrams, partial matches with ILIKE, and natural language full-text search.

Welcome to The RailsNotes Newsletter — Issue #17! This issue is all about enums!

Hey! 👋 Welcome back to another issue of the RailsNotes newsletter! This issue is all about enums! You heard me right, enums. Often unappreciated (in my opinion), there’s actually a lot to them and a lot of cool enum patterns that Rails/Ruby supports.

The featured article this week covers a design pattern I love, the value object. Basically, we create a PORO (plain ruby object) to encapsulate the enum values and backing logic. We then set up our model to use our value object, pulling in the required enum statuses and behaviour from there.

The other articles this week cover different approaches to using enums, plus a handy ActiveRecord tip for sorting by enum values with #in_order_of.

Also, PgAnalyze is again sponsoring this week’s newsletter, and they’ve got another free ebook to share! This one covers building full-text searches with plain Rails and PostgreSQL and includes tips for speeding up queries and implementing trigram search. As usual, it’s got great diagrams like this one below to explain things — 

One of the many cool and handy illustrations that PgAnalyze loves to include in their eBooks.

Enough said, let’s go!

~ FEATURED ARTICLE ~

You, overwhelmed by enum values, wishing you’d implemented the value-object pattern you read about a few weeks ago.

This is the article I mentioned earlier, in the intro section of this newsletter. Pawel dives into Rails enums, specifically using the value-object design pattern to encapsulate sophisticated enum behaviour.

I love this pattern! I’ve used it across various projects, and find it very useful.

I won’t say much more (it’s best seen in code), but it’s a handy pattern and worth checking out, even just to have in your back pocket 👖. It’s interesting too seeing how easy Rails makes it to implement, and you don’t have to sacrifice any of the yummy syntactic sugar that Rails typically gives you when you define an enum.

Well worth a read!

~ MORE ARTICLES  ~

This is a handy primer to Rails enums and walks you through different approaches for implementing them (fixed integer keys etc), plus shows you the syntactic sugar methods that Rails provides you.

Yaroslav (author of the SupeRails blog) always has interesting and punchy, to-the-point articles, and this one is no different. More on the basic side, but handy for beginners or a refresher.

This is a much more detailed 🔍️ look into enums in Rails, covering all the different things you can do with them, methods you can access, etc. Topics include typecast helpers, updating with bang! methods, scoping, defaults and more.

A great in-depth look into enums and everything that Rails gives you to work with them!

Another great tip from Matt/BoringRails — this one covers using the #in_order_of ActiveRecord method to pull out records in a specific enum ordering.

Pretty cool and easily digestible tip; Convenient if you work with enums a lot, or models with a lots of enum statuses. For a quick breakdown, I’ve included it as the handy tip below 👇️, although the article is well worth the read for the extra info.

~ ⚒️ HANDY TIP ~ 

→ Sort models by enum values with #in_order_of

Rails 7 introduced the handy #in_order_of method (docs), which lets us retrieve records in a certain order (using the database to perform the ordering, not Ruby).

We can combine this with enum statuses to pull out records, ordered by their statuses, like below. This could be handy for showing an ordered list on an index route, etc 👇️ 

class Product < ApplicationRecord
  STATUS = {
    created: 0,
    private: 1,
    out_of_stock: 2,
    live: 3
  }
end

# get Products in given enum ordering — 
Product.all.in_order_of(:status, %w[out_of_stock live created private])