#​548 — April 15, 2021

Read on the Web

🖋 A surprisingly quiet week in Ruby land, but we've found some good releases, we've got a tip of the week, and hope you're having a great week wherever you are :-) As always, if you have anything to send in, hit "reply" and let me know. Thanks for your support!
__
Peter Cooper, your editor

Ruby Weekly

Hotwire: Reactive Rails with No JavaScript? — We’ve touched on Hotwire a few times since it was unveiled in January, but this is the deepest practical insight we’ve seen into how to actually work with it to create reactive Rails applications with Turbo and only a pinch of custom JavaScript.

Vladimir Dementyev

Rails Controller Patterns and Anti-Patterns — The last in a series of posts about Rails patterns and anti-patterns reaches controllers. Previous excursions covered patterns and anti-patterns for views and for models, if you want the whole set :-)

Nikola Đuza

Optimize Ruby App Performance in Real-Time — Visualize Ruby performance using detailed flame graphs to identify bottlenecks and latency. Debug and optimize your code by tracing requests across web servers, databases, and services with Datadog APM. Start a free trial today.

Datadog APM sponsor

The Ruby Unbundled Series: Release Features Faster by Slowing Down“Roll forward slowly, but always rollback quickly.” In short, gain confidence in your software before pushing features to all users.

Darren Broemmer (Engine Yard)

Quick Bits

📘 Articles & Tutorials

Building Lightweight Components with Rails Helpers and Stimulus — A nice approach to reusable components with minimal code.

Matt Swanson

Why You Should Avoid Models in Rails Migrations“Allowing migrations to rely on only the database as a source of truth enables all developers on the team to run migrations without issue.”

Jake Yesbeck

Build a Rails App with ActiveRecord and CockroachDB — See how easy it is to add the ActiveRecord CockroachDB Adapter and build a distributed app for free.

Cockroach Labs sponsor

Ruby 3.0 Changes How Methods of Subclassed Core Classes Work — Probably doesn’t affect too many folks, but it is an interesting change.

Vasiliy Ermolovich

Creating a UDP Server with Ractors — More Ractors fun for your learning pleasure.

Claus Lensbøl

Exploring the `super` Keyword
Paweł Dąbrowski

Tip: How to Delete Jobs From Sidekiq Retries
Tomasz Wróbel

💻 Jobs

Senior Software Engineer (US - Remote-Friendly) — Snapdocs is going through a hyper-growth phase, looking for empathetic Senior Software Engineers as we scale our product and team.
Snapdocs

Wynter Is Looking for Developers to Join Its Research Panel — Give feedback on digital products and landing pages, get paid $15-$50 per survey. Low-key commitment, 10-15 mins per survey.
Wynter Research Panels

Find Ruby Jobs with Hired — Take 5 minutes to build your free profile & start getting interviews for your next job. Companies on Hired are actively hiring right now.
Hired

🛠 Code and Tools

Maily 2.0: A Rails Engine to Preview Emails — Automatically picks up all your emails and makes them accessible from a Web-based dashboard.

Marc Anguera

connection_pool: A Generic Connection Pooling Library — Lots of other systems have connection pools built in, but what if you want a generic one to use with whatever you wish?

Mike Perham

OmbuLabs Teaches you to Pitch a Maintenance Project to your (Non-Technical) Boss

OmbuLabs sponsor

Alba 1.0: The Fastest JSON Serializer for Ruby? — A bold claim, but worth checking out. It supports JRuby and TruffleRuby in addition to regular CRuby.

Okura Masafumi

HexaPDF 0.15.0: A Ruby PDF Creation and Manipulation Library — This release adds support for flattening annotations – that is, making annotations part of the page content itself. Note that the project is AGPL licensed.

Thomas Leitner

Ancestry 4.0: Organize An Active Record Model Into a Tree Structure — If you’ve got hierarchical or tree-like data to represent in Active Record, this is for you.

Stefan Kroes

Clearance 2.4: Email and Password-Based Rails Authentication2.4.0 adds support for signed cookies to prevent token timing attacks.

thoughtbot, inc.

💡 Tip of the Week

Variable Pinning (Part 1 of 2)

Ruby 2.7 introduced pattern matching as an experimental feature. As of Ruby 3.0, only small parts of pattern matching are still experimental, which means we can learn about the stable parts.

Variable pinning is a new feature with pattern matching which we'll discuss in two consecutive tips. It's first necessary for us to understand the goals of pattern matching. From the docs, "Pattern matching is a feature allowing deep matching of structured values: checking the structure and binding the matched parts to local variables."

Pattern matching uses the case/in/else expression, similar to the case/when/else expression. It allows us to match patterns, not just exact values:

case [1,2]
in [1,a]
  "pattern match: a: #{a}"
in [1,2]
  "second case"
end
=> "pattern match: a: 2"

Woah! We can see that it matched the [1,a] case before the [1,2] case because our array matched the pattern [1,a]. And what's more: the value of a was then set to 2, the second element of our array in the case statement.

You may be wondering what would happen if we wanted to try pattern match against an existing local variable. Say we had already defined a before the case statement:

a = 3

case [1,2]
in [1,a]
  "pattern match: a: #{a}"
in [1,2]
  "second case"
end
=> "pattern match: a: 2"

Uh-oh. What's going on? It's telling us a is 2 and seems to be overriding our local variable a, which has a value of 3. This is where pinning comes in! If we wanted to use the local variable a, we would use the pin operator, ^ to signify that we were referrring to our local variable:

a = 3

case [1,2]
# We'll now use ^a
in [1,^a]
  "pattern match: a: #{a}"
in [1,2]
  "second case"
end
=> "second case"

And we can see that with the pin operator, we no longer match the first case, which would be [1,3]. Just to confirm we could match the first case if the second element in our array was 3, let's change our array to be [1,3]:

a = 3

case [1,3]
in [1,^a]
  "pattern match: a: #{a}"
in [1,2]
  "second case"
end
=> "pattern match: a: 3"

Check back in next week for another use case of variable pinning!

This week’s tip was written by Jemma Issroff.