Use the Attributes API to make your Rails models more communicative
ActiveRecord is the powerful object-relational mapper at the heart of Ruby on Rails. By default, it gives you tools to quickly and easily create new database tables and map them to domain models. It follows the ethos of “convention over configuration” that David Heinemeier Hansson coined with the release of Rails. As such, with little application code, you get a powerful, database-backed model that Just Works™.
However, few lines of code do not, necessarily, mean that the lines that are there are easy to understand. Does this model have a
description? How is that
expiryfield encoded, as a Date or a Time? What fields exist on this table, again? These are examples of common questions when working in a Ruby on Rails application.
To alleviate some of these issues, you can use the Attributes API when defining your models to make them more explicit. You can also use richer data types for your fields to ease working with subsets of your models. This article will share the history of the Attributes API, then show some concrete examples of using it.
Duplicate cookies in Ruby on Rails
Ruby on Rails has an easy-to-use cookie store for managing state between requests. It has affordances for storing clear-text values, tamper-proof signed values, and encrypted values. I previously showed how you can make good use of encrypted values for handling ActionCable authentication. However, there is a case where you might end up with duplicate cookies in Ruby on Rails applications.
This article discusses cookies, shared cookies, and how the use of the Ruby on Rails cookie store may lead to apparently duplicate cookies. From that, we’ll end with three rules of thumb for using cookies and avoiding the issue.
3 Ways to Make Arel a Joy
Arel, the SQL syntax tree constructor library backing ActiveRecord, allows you to express your SQL queries without the use of fragments. ActiveRecord uses it internally to represent a variety of queries. It does this transparently using the traditional
where(key: value)syntax that we’ve seen since the early days of Rails.
In cases where you only need to write simple query predicates, the traditional syntax is what you should reach for, full stop. However, when you need to write a more complex query like grouped pagination or null-based ordering, I recommend reaching for Arel.
However, because Arel considers itself a “framework framework,” it’s not a truly enjoyable to use out-of-the-box. This article shares three ways to make Arel a joy to use.
Null-based ordering in ActiveRecord
When designing your domain model for an application, the natural solution might end up using a
nilto model the absence of a value. In these cases, you might need to reach for null-based ordering within your database. When you’re writing a Ruby on Rails application, you’re most likely going to use ActiveRecord as the interface to your database. While ActiveRecord supports most queries out-of-the-box, sometimes you have to go off the beaten path.
Null-based ordering is one of those situations. Since ActiveRecord’s ordering works based on simple
key: :directionpairs, it is hard to perform null-based ordering outside of using the built-in behavior of your database. This article outlines two ways you can structure this type of null-based ordering, along with the caveats of using them.
Implementing account impersonation in ActionCable
Account impersonation is when you allow accounts (usually privileged accounts, e.g. support staff or developers) to operate your Rails application as if they are the owner of another account entirely. It’s a helpful feature to have when diagnosing issues that your customers write in about. There are plenty of gems that implement impersonation for your Rails controllers, but I wasn’t able to turn up any suggestions for implementing this for ActionCable.
This post outlines a simple method for adding impersonation to your Rails application in both your controllers and your ActionCable channels. I discuss some ActionCable features that are not well-documented and that I found a little confusing, then show examples of how to use the same pattern for identifying both your active account and your impersonating account — called a “shadower” in this article — in your channels.
A checklist for reviewing Rails database migrations
Software teams often cite code reviews as a primary means for ensuring quality and reducing bugs in their code. However, without high quality reviews, the efficacy of this practice is questionable. In most places that I’ve worked, a change requires only one code review (either through necessity due to team size or through informal norms). When this is the case, the code review becomes a taxing process where, if you’re not on your game, bugs or maintainability issues can start to leak into production. This means that it often falls to the senior engineers to do code reviews. However, relying entirely on the seniors means that they become a bottleneck in the process. When it comes to “dangerous” changes like Rails database migrations, the bottleneck of relying on a small subset of the team can mean that velocity drops. Or, to keep up velocity, you make code reviews less stringent and quality drops.
In try to “scale myself” for my team, I have started to experiment with checklists for performing code reviews. The first one that I wrote up is a checklist for reviewing Rails database migrations. We run on Heroku, which means that zero-downtime migrations are easy to do, as long as you write your migrations correctly. I intend this checklist to help more junior teammates do as thorough of a job in reviewing as I do. Going forward, I want to make more checklists for doing different types of code reviews, to further scale myself for my team.
Grouped pagination in ActiveRecord
Sometimes, designers will mock-up an extremely usable page that they’ve thought about and tested. Once they’re done and they bring it to you to implement, you look at it and think, “how on Earth can I do that efficiently?” One such case happened at work recently.
We were working on a “command center” of sorts where we show our customers a list of upgrades in various states. The design called for what looked like three different lists of records with each table consisting of records in a state. Since a customer can have potentially dozens of these records, we knew we wanted to paginate the page. The wrinkle in setup was that the pagination should consider the full list of records as the dataset, not each list individually. This caused us to wonder how we can efficiently implement grouped pagination in ActiveRecord.
Finding Rails migrations
Sometimes, I find myself working across several branches helping different teammates with their stories. Often, these branches use Rails migrations to easily manage the database changes that need to be made to support the work. This means that I end up running migrations from many different branches. Because I am human, I often forget to roll those migrations back before switching branches. When a destructive migration has to happen as part of a branch, it leaves me in a situation where I have several migrations that I need to roll back at any given time. In addition, they might be interleaved with migrations that exist on the
masterbranch if it’s a longer-running branch.