Michael Anhari

Two features of Ruby that helped me demystify Rails

A blue crystal ball next to an open book with the pages turning in the wind

A lot has been said around the idea that Ruby on Rails is a web framework with "too much magic". For the most part, I think that is referring to the extensive use of metaprogramming in Rails and ActiveRecord.

For example, Rails generates all kinds of methods dynamically based on the underlying structure of the database. If you have a Book model with a title attribute, you can use methods like Book.find_by_title("The Lord of the Rings"). This is very convenient, but can be confusing when grepping for find_by_title in your codebase doesn't yield any results. You also won't find it in app/models/book.rb. It's just something that's been generated for you behind the scenes. This kind of "magic" I can understand the argument against, and won't be the subject for this post.

I think another contributing factor to Rails feeling very magical is actually inherited from Ruby.

Ruby syntax isn't omakase

"Convention over configuration" and "Rails is omakase" 1 have long been two of the selling points of its creators.

The first makes the argument that the fewer decisions a developer has to make, the more productive and happy they will be. The second expands upon that by saying Rails makes a large number of decisions for developers, which sounds controversial or arrogant but ultimately leads to a better developer experience that the core team beleives in.

On the other hand, the language powering this off-the-shelf solution has quite a contrarian stance. Ruby has deep roots in being an expressive language with optional syntax rules. It has brought a lot of joy to developers by allowing functionally equivalent code in ways that appeal to individual tastes. It sacrifices conformity for joy. Configuration over convention.

As a result, a lot of tools have sprung up over the years to try and standardize how Ruby looks in a codebase. I'm a huge in fan in using one of these tools. Shutting down the process in your brain that is needed to nudge indentation or add line breaks is hugely beneficial in my experience. It also leads to a homogenized codebase that becomes faster to grok.

Now, all of this has been leading up to two syntax features that I think can make Ruby harder to parse.

Syntax Feature 1: Optional method parentheses

It probably sounds silly. But I was months into learning Rails before I realized that has_many and belongs_to were simply methods coming from ActiveRecord. Please be kind and keep in mind that Rails was the first tech stack I ever picked up. Still, I don't think I am alone in this.

How much sooner would I have grasped that bit of insight if they looked like this?

has_many(:articles)

instead of

has_many :articles

This seems like such a tiny difference, but I think the implications are huge. It reminds me of the knobs on my stove. Half of the time I turn on the front burner when I wanted to use the one in the back because the labeling on the stove is unclear. At its heart, it's another demonstration of the impact of clear design and the importance of design thinking.

Syntax Feature 2: Optional hash braces for final method arguments

In Ruby, curly braces around hashes are optional when they are the last argument in a method. I feel like this issue compounds with the first, at least for me.

# which is clearer to you?
has_many :articles, through: :topic

has_many(:articles, { through: :topic })

What about in a embedded Ruby file?

#shorthand form
<%= f.input :user_id,
            collection: User.order(:name),
            label_method: :full_name,
            value_method: :id
%>

# longhand form
<%= f.input(
      :user_id,
      {
        collection: User.order(:name),
        label_method: :full_name,
        value_method: :id
      }
    )
%>

As an experienced Rails developer I'm at the point where I am very comfortable with the first syntax after years of practice. However, if I was just picking up the framework again, I think the latter version is easier to understand. I don't have to remember these two quirks of optional Ruby syntax to get the gist.

Footnotes

1.

omakase is Japanese for "I leave it up to you", and is commonly used in sushi restaurants where patrons defer their dining decisions to the chef.

↩ī¸Ž

Newsletter

I'm working on sending out a weekly newsletter. I'll make it as easy as possible to unsubscribe at any time.