Concerns in Rails: Everything You Need to Know

Ask questions Research chat →

https://www.akshaykhot.com/how-rails-concerns-work-and-how-to-use-them/ · scraped

rails

Attachments

Scraped Content

— 1744 words · 2026-02-14 17:44:28 UTC ·

Excerpt

![](https://prod-files-secure.s3.us-west-2.amazonaws.com/871f1661-80b8-4d0c-ac3b-2adfc6ff4c66/7beb944b-8380-435e-969c-caf4fc94da65/concerns-5.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664XPPXNUZ%2F20260214%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260214T174427Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEEaCXVzLXdlc3QtMiJHMEUCIQDIcc3gAtgo1WiplVklsjSP2sgq8lBeXtAkxi98%2BwBtuwIgO7pc6ZDU1N3DYzNJWfiAuUDjIfUZhgUsqtezIrZHmTUq%2FwMIChAAGgw2Mzc0MjMxODM4MDUiDJsTRLoOVr%2FAa3oVJyrcA0hQjb%2B2409jzDcaqhxLsRfPs4cTGCAJCkQmj5Sg96WmUQTiJSFpKqKdkej%2BRMXMJ8Htl0ODHnpYEy8EeV9%2FoAYng7TocnYmiLmOqBlJt2U%2BU3%2FajWt1muD2qLVpArOUn2kgtzHyauGs%2Fn7x1BxhKxIO7w9GvrcqxGkAvzRXDxVFng8TIWfkJ52jWT8TepTNrapJn%2BD1z4OjCISZ1qHUE93%2F9Rdlhykx9oOyQbyz12C10UOcvJt1eXkEBgCgO1XXCj8%2BCMlYZMzYWE0etBjulXEkb2mAFg7l7vI5nmNrHYEmaCHKuJzpwWFRwv7DW9UpGpcpntK%2FaeT4npHci2dEIPw6lW30mhBTvSL099Xb5Mj66Nm%2Fn%2B0QerrOS4%2FMuf2tkfdk4bgSPN5K8Px7dtKEV6kUqRHJt%2BJ55p11
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/871f1661-80b8-4d0c-ac3b-2adfc6ff4c66/7beb944b-8380-435e-969c-caf4fc94da65/concerns-5.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664XPPXNUZ%2F20260214%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260214T174427Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEEaCXVzLXdlc3QtMiJHMEUCIQDIcc3gAtgo1WiplVklsjSP2sgq8lBeXtAkxi98%2BwBtuwIgO7pc6ZDU1N3DYzNJWfiAuUDjIfUZhgUsqtezIrZHmTUq%2FwMIChAAGgw2Mzc0MjMxODM4MDUiDJsTRLoOVr%2FAa3oVJyrcA0hQjb%2B2409jzDcaqhxLsRfPs4cTGCAJCkQmj5Sg96WmUQTiJSFpKqKdkej%2BRMXMJ8Htl0ODHnpYEy8EeV9%2FoAYng7TocnYmiLmOqBlJt2U%2BU3%2FajWt1muD2qLVpArOUn2kgtzHyauGs%2Fn7x1BxhKxIO7w9GvrcqxGkAvzRXDxVFng8TIWfkJ52jWT8TepTNrapJn%2BD1z4OjCISZ1qHUE93%2F9Rdlhykx9oOyQbyz12C10UOcvJt1eXkEBgCgO1XXCj8%2BCMlYZMzYWE0etBjulXEkb2mAFg7l7vI5nmNrHYEmaCHKuJzpwWFRwv7DW9UpGpcpntK%2FaeT4npHci2dEIPw6lW30mhBTvSL099Xb5Mj66Nm%2Fn%2B0QerrOS4%2FMuf2tkfdk4bgSPN5K8Px7dtKEV6kUqRHJt%2BJ55p11rys4taJ39Ppx9WEpvJIuEuT5Q8U3n55i8CCSR5dou25HBaUiChWjUDg036dBebNvg6MowXs1BIXYORKtoaDLDBdn%2BU2NsEuQZwHjdY4b6IiOYVlEBADQ6ILE0vuCHGo921oljV7F%2BqHiCrUU0fxdh6CNRYqz%2ByI8vYQGdrkp%2FIZ7E4vcYkeycBJE3PlD3Pp8UQgnIFy7RJszTzDaosGqVZsWMPrRwswGOqUBeOlJTFURLmcj83RE3il6IdwMYzxLq%2Fqbno%2FVqqBhzOYm2oLRXshVlVnVm2uzo2PXRjb%2FGx4zzfP%2FAft9QAyAU3MEOdCnln7zzmMh%2B44kpEPJUMqT8YKlz47ZBlWwJXp6o%2FBWDqmFELKWwP5DskznRDGvArZvhuScgEYcLbdBOpLHSBGJKSMbc8UmHe2SCfwCi5f1zs38fiKWjNa1kK14X%2BuhLKb6&X-Amz-Signature=719ed6c17721064832bc9d1be40ea13f6cfe51132cc85d4b07ab86cfef677059&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) P.S. I originally published this post last year, when I was just starting to learn Rails. Since then, I've learned a few more things and hence decided to edit, revise, polish, and re-publish it. Also, a ton of new subscribers have joined the email list, and I thought you all might find it helpful. Many Rails applications, including the framework itself, make heavy use of concerns. However, if you are new to Rails, concerns can be confusing to understand. When I started learning Rails last year, concerns were one of the topics that took a really long time for me to understand. The Rails guide on concerns mixes in unrelated concepts such as validations, migrations, and views, making it overwhelming to understand the purpose of concerns to someone new to Rails. The Rails API documentation doesn’t help either. It starts with the assumption that the reader is already familiar with the problem concerns are trying to solve, and goes on to provide the solution, only adding to the confusion. So I did some reading and found the web has many interesting nuggets of concern wisdom scattered around, like this blog post from DHH demonstrating the usage of concerns, or these answers from the A May of WTFs thread from the Core Rails members explaining concerns with a metaphor of writing. This blog post attempts to summarize these scattered pieces of information to paint a coherent picture, showing you how concerns can help you write better code. Here’s what I want you to get from this article: - What is a concern? - Why and when should you use concerns? - How to use a concern? - The rationale behind concerns Sounds interesting? Let's begin... ## What is a Concern? > A concern Xavier Noria A Rails concern is just a plain Ruby module that extends the ActiveSupport::Concern module provided by Rails. Here’s a concern named Taggable. ```plain text module Taggable extend ActiveSupport::Concern included do # any code that you want inside the class # that includes this concern end class_methods do # methods that you want to create as # class methods on the including class end end ``` In Ruby, when a class includes another module, it gets all the methods defined in that module as if it had defined them. You can still do this with a concern, which I repeat, is just another Ruby module. However, turning a Ruby module into a Rails concern allows us to do the following interesting things: 1. Include class methods in addition to instance methods 2. Define additional code such as validations, callbacks, or constants on the including class. A concern does this by providing the following two blocks: included - Any code inside this block is evaluated in the context of the including class. If Post class includes a concern, anything inside the included block will be evaluated as if it was written inside the Post class. - Typically, this block is used to define Rails macros like validations, associations, and scopes. Any methods you create here become instance methods of the including class. class_methods - Any methods that you add here become class methods on the including class. - Alternatively, you can create a nested module named ClassMethods instead of the class_methods block to define the class methods. See the API docs for an example. For more details on evaluating the code in the context of another class, please read the following article. ![](https://prod-files-secure.s3.us-west-2.amazonaws.com/871f1661-80b8-4d0c-ac3b-2adfc6ff4c66/dcece4e9-28e3-475e-93e4-af9475ad3de2/Akshay-3.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664XPPXNUZ%2F20260214%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260214T174427Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEEaCXVzLXdlc3QtMiJHMEUCIQDIcc3gAtgo1WiplVklsjSP2sgq8lBeXtAkxi98%2BwBtuwIgO7pc6ZDU1N3DYzNJWfiAuUDjIfUZhgUsqtezIrZHmTUq%2FwMIChAAGgw2Mzc0MjMxODM4MDUiDJsTRLoOVr%2FAa3oVJyrcA0hQjb%2B2409jzDcaqhxLsRfPs4cTGCAJCkQmj5Sg96WmUQTiJSFpKqKdkej%2BRMXMJ8Htl0ODHnpYEy8EeV9%2FoAYng7TocnYmiLmOqBlJt2U%2BU3%2FajWt1muD2qLVpArOUn2kgtzHyauGs%2Fn7x1BxhKxIO7w9GvrcqxGkAvzRXDxVFng8TIWfkJ52jWT8TepTNrapJn%2BD1z4OjCISZ1qHUE93%2F9Rdlhykx9oOyQbyz12C10UOcvJt1eXkEBgCgO1XXCj8%2BCMlYZMzYWE0etBjulXEkb2mAFg7l7vI5nmNrHYEmaCHKuJzpwWFRwv7DW9UpGpcpntK%2FaeT4npHci2dEIPw6lW30mhBTvSL099Xb5Mj66Nm%2Fn%2B0QerrOS4%2FMuf2tkfdk4bgSPN5K8Px7dtKEV6kUqRHJt%2BJ55p11rys4taJ39Ppx9WEpvJIuEuT5Q8U3n55i8CCSR5dou25HBaUiChWjUDg036dBebNvg6MowXs1BIXYORKtoaDLDBdn%2BU2NsEuQZwHjdY4b6IiOYVlEBADQ6ILE0vuCHGo921oljV7F%2BqHiCrUU0fxdh6CNRYqz%2ByI8vYQGdrkp%2FIZ7E4vcYkeycBJE3PlD3Pp8UQgnIFy7RJszTzDaosGqVZsWMPrRwswGOqUBeOlJTFURLmcj83RE3il6IdwMYzxLq%2Fqbno%2FVqqBhzOYm2oLRXshVlVnVm2uzo2PXRjb%2FGx4zzfP%2FAft9QAyAU3MEOdCnln7zzmMh%2B44kpEPJUMqT8YKlz47ZBlWwJXp6o%2FBWDqmFELKWwP5DskznRDGvArZvhuScgEYcLbdBOpLHSBGJKSMbc8UmHe2SCfwCi5f1zs38fiKWjNa1kK14X%2BuhLKb6&X-Amz-Signature=a42323fcf3e64141b0ce28d627c22b8850c8fb1df4b060b014931c5767e64a9e&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) ![](https://prod-files-secure.s3.us-west-2.amazonaws.com/871f1661-80b8-4d0c-ac3b-2adfc6ff4c66/086aa2a0-0052-4648-9cda-fde088f5a1fc/eval_diff.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664XPPXNUZ%2F20260214%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260214T174427Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEEaCXVzLXdlc3QtMiJHMEUCIQDIcc3gAtgo1WiplVklsjSP2sgq8lBeXtAkxi98%2BwBtuwIgO7pc6ZDU1N3DYzNJWfiAuUDjIfUZhgUsqtezIrZHmTUq%2FwMIChAAGgw2Mzc0MjMxODM4MDUiDJsTRLoOVr%2FAa3oVJyrcA0hQjb%2B2409jzDcaqhxLsRfPs4cTGCAJCkQmj5Sg96WmUQTiJSFpKqKdkej%2BRMXMJ8Htl0ODHnpYEy8EeV9%2FoAYng7TocnYmiLmOqBlJt2U%2BU3%2FajWt1muD2qLVpArOUn2kgtzHyauGs%2Fn7x1BxhKxIO7w9GvrcqxGkAvzRXDxVFng8TIWfkJ52jWT8TepTNrapJn%2BD1z4OjCISZ1qHUE93%2F9Rdlhykx9oOyQbyz12C10UOcvJt1eXkEBgCgO1XXCj8%2BCMlYZMzYWE0etBjulXEkb2mAFg7l7vI5nmNrHYEmaCHKuJzpwWFRwv7DW9UpGpcpntK%2FaeT4npHci2dEIPw6lW30mhBTvSL099Xb5Mj66Nm%2Fn%2B0QerrOS4%2FMuf2tkfdk4bgSPN5K8Px7dtKEV6kUqRHJt%2BJ55p11rys4taJ39Ppx9WEpvJIuEuT5Q8U3n55i8CCSR5dou25HBaUiChWjUDg036dBebNvg6MowXs1BIXYORKtoaDLDBdn%2BU2NsEuQZwHjdY4b6IiOYVlEBADQ6ILE0vuCHGo921oljV7F%2BqHiCrUU0fxdh6CNRYqz%2ByI8vYQGdrkp%2FIZ7E4vcYkeycBJE3PlD3Pp8UQgnIFy7RJszTzDaosGqVZsWMPrRwswGOqUBeOlJTFURLmcj83RE3il6IdwMYzxLq%2Fqbno%2FVqqBhzOYm2oLRXshVlVnVm2uzo2PXRjb%2FGx4zzfP%2FAft9QAyAU3MEOdCnln7zzmMh%2B44kpEPJUMqT8YKlz47ZBlWwJXp6o%2FBWDqmFELKWwP5DskznRDGvArZvhuScgEYcLbdBOpLHSBGJKSMbc8UmHe2SCfwCi5f1zs38fiKWjNa1kK14X%2BuhLKb6&X-Amz-Signature=85a53171ba52880550bdca2654e9a167e114bf2c6ad23a9f67e363c3552a1421&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) Okay, by now, you must have a pretty good understanding of what a concern is. In the next section, we'll learn why and when should you use one, instead of a plain Ruby module. ## Why and When Should You Use Concerns? Using a concern lets you extract the common logic from different classes into a reusable module. Consider two common models: Post and Comment, which represent a blog post and its comments, just like the one you're reading right now. A post has rich text and it can have multiple comments. In addition to the code specific to these models, both classes contain the code that handles their visibility, specifically: 1. visible_to attribute, 2. is_visible instance method, and 3. all_visible class method ```plain text # post.rb class Post < ApplicationRecord belongs_to :author has_many :comments, dependent: :delete_all has_rich_text :content validates :title, presence: true, length: { minimum: 2 } validate :has_valid_content # common data attr_accessor :visible_to # common instance method def is_visible? visible_to.present? end def has_valid_content # some code end # common class method def self.all_visible all.select { |item| item.is_visible? } end end # comment.rb class Comment < ApplicationRecord belongs_to :post validates :commenter, :body, presence: true # common data attr_accessor :visible_to # common instance method def is_visible? visible_to.present? end # common class method def self.all_visible all.select { |item| item.is_visible? } end end ``` You must have noticed the code that checks the model's visibility is duplicated in both classes. You can imagine there could be other similiar models that need to control their visibility in the same way. It would be nice if there was a way to abstract the visibility-related code. Concerns let you do exactly that. ## How to Use a Concern? Let’s create a Visible concern to extract the visibility-related code from the Post and Comment models. We'll put the attribute and the instance method inside the included block and the class method inside the class_methods block. 💡 The Visible concern deals with an entity’s visibility, its primary concern is to check if that entity is visible or not. ```plain text # visible.rb module Visible extend ActiveSupport::Concern # The code inside the included block is evaluated # in the context of the class that includes the Visible concern. # You can write class macros here, and # any methods become instance methods of the including class. included do attr_accessor :visible_to def is_visible? visible_to.present? end end # The methods added inside the class_methods block (or, ClassMethods module) # become the class methods on the including class. class_methods do def all_visible all.select { |item| item.is_visible? } end end end ``` To use this concern, you include the module as usual. For example, if the Post model wants the visibility functionality, it includes the Visible concern. Including this concern adds the visible_to attribute, is_visible instance method, and the all_visible class method to the Post class. Let's see how the Visible concern simplifies both Post and Comment classes. Let's run the following test to ensure none of the existing behavior in the Post class was changed. It passes with flying colors. > If you're following along with me, here's your challenge: write the passing test for the ```plain text Comment ``` ```plain text Visible ``` ## The Rationale Behind Concerns At this point you might be wondering: what’s the point of all this? If we are trying to abstract some common behavior at a central location, can’t we simply create a new class, encapsulating the query in a stand-alone object? And you’d be right. You can create a class containing the shared code, instantiate it, and use it. However, concerns are often just the right amount of abstraction, resulting in a friendlier API. All the methods you need are right there, on the primary object, and you don’t need to introduce an intermediate object like visibility_manager to access the shared code. Which code is more readable? I admit, not everyone will agree here. In fact, since writing this post, a few people raised concerns (no pun intended!) that using concerns is a bad practice, composition is better than inheritance, concerns make the code difficult to read and test, they bloat your models, and so on and so on. Personally, I found concerns very refreshing; coming from the C#/.NET world, I was used to creating Managers, Services, Commands, etc. all the time. Now I mostly prefer concerns, as they result in cleaner APIs on the models and I haven’t run into any headaches with testing etc. Regarding readability, Rails makes heavy use of concerns. They are everywhere! My experience reading the Rails codebase has been a delight. I’ve been in the Rails ecosystem for just over a year, and find Rails source code an absolute pleasure to read. At first, I thought the concerns (and modules) were confusing (so much hidden code!), but now I just like to think of them as neatly organized drawers. Agree, the room (model) has too many drawers, but at least everything is neatly organized, and once I find the concerned file, I know what’s going on. Nowadays, if I come across a new feature, I just open the Rails source code and see how it's implemented. Personally, I find reading the source much more efficient than the guides and sometimes, the API. Finally, I haven't yet come across code that was difficult to read and test due to concerns. Also, no one is preventing you from using composition and creating services and managers and the whole lot to separate your dependencies. I have nothing against them. If you want a much more nuanced post on concerns and various debates surrounding them, I recommend you read Jason Swett's excellent article: When used intelligently, Rails concerns are great. So if you're still confused between the two approaches, here's what I recommend: write both versions side-by-side, take a look at them both, and choose whichever one you like. It's that simple! Here’s how DHH addresses this concern (no pun intended) ;) > So that’s another way of putting this: It’s a writing style. Like using subheads to explain subservient ideas within a broader context. You could A May of WTFs That’s what concerns are: A way to group related methods together, while still living under a single class. It’s structured writing. That's a wrap. I hope you liked this article and you learned something new. If you want to go even deeper on concerns, I highly recommend you read this excellent article from Jorge Manrubia, a developer at 37signals. It's one of the best programming articles I've read in a long time. ![](https://prod-files-secure.s3.us-west-2.amazonaws.com/871f1661-80b8-4d0c-ac3b-2adfc6ff4c66/598f999b-9b2d-4707-b373-21e8d25a8374/apple-touch-icon.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664XPPXNUZ%2F20260214%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260214T174427Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEEaCXVzLXdlc3QtMiJHMEUCIQDIcc3gAtgo1WiplVklsjSP2sgq8lBeXtAkxi98%2BwBtuwIgO7pc6ZDU1N3DYzNJWfiAuUDjIfUZhgUsqtezIrZHmTUq%2FwMIChAAGgw2Mzc0MjMxODM4MDUiDJsTRLoOVr%2FAa3oVJyrcA0hQjb%2B2409jzDcaqhxLsRfPs4cTGCAJCkQmj5Sg96WmUQTiJSFpKqKdkej%2BRMXMJ8Htl0ODHnpYEy8EeV9%2FoAYng7TocnYmiLmOqBlJt2U%2BU3%2FajWt1muD2qLVpArOUn2kgtzHyauGs%2Fn7x1BxhKxIO7w9GvrcqxGkAvzRXDxVFng8TIWfkJ52jWT8TepTNrapJn%2BD1z4OjCISZ1qHUE93%2F9Rdlhykx9oOyQbyz12C10UOcvJt1eXkEBgCgO1XXCj8%2BCMlYZMzYWE0etBjulXEkb2mAFg7l7vI5nmNrHYEmaCHKuJzpwWFRwv7DW9UpGpcpntK%2FaeT4npHci2dEIPw6lW30mhBTvSL099Xb5Mj66Nm%2Fn%2B0QerrOS4%2FMuf2tkfdk4bgSPN5K8Px7dtKEV6kUqRHJt%2BJ55p11rys4taJ39Ppx9WEpvJIuEuT5Q8U3n55i8CCSR5dou25HBaUiChWjUDg036dBebNvg6MowXs1BIXYORKtoaDLDBdn%2BU2NsEuQZwHjdY4b6IiOYVlEBADQ6ILE0vuCHGo921oljV7F%2BqHiCrUU0fxdh6CNRYqz%2ByI8vYQGdrkp%2FIZ7E4vcYkeycBJE3PlD3Pp8UQgnIFy7RJszTzDaosGqVZsWMPrRwswGOqUBeOlJTFURLmcj83RE3il6IdwMYzxLq%2Fqbno%2FVqqBhzOYm2oLRXshVlVnVm2uzo2PXRjb%2FGx4zzfP%2FAft9QAyAU3MEOdCnln7zzmMh%2B44kpEPJUMqT8YKlz47ZBlWwJXp6o%2FBWDqmFELKWwP5DskznRDGvArZvhuScgEYcLbdBOpLHSBGJKSMbc8UmHe2SCfwCi5f1zs38fiKWjNa1kK14X%2BuhLKb6&X-Amz-Signature=77441c90e53271870fee8aab994e9110f895c3ee27dcdf1fd3a8b4d69bf0bbf5&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) ![](https://prod-files-secure.s3.us-west-2.amazonaws.com/871f1661-80b8-4d0c-ac3b-2adfc6ff4c66/a2771bb8-6cce-4215-bf8a-3539c39f868c/37s-dev-vanilla-rails-is-plenty.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664XPPXNUZ%2F20260214%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260214T174427Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEEaCXVzLXdlc3QtMiJHMEUCIQDIcc3gAtgo1WiplVklsjSP2sgq8lBeXtAkxi98%2BwBtuwIgO7pc6ZDU1N3DYzNJWfiAuUDjIfUZhgUsqtezIrZHmTUq%2FwMIChAAGgw2Mzc0MjMxODM4MDUiDJsTRLoOVr%2FAa3oVJyrcA0hQjb%2B2409jzDcaqhxLsRfPs4cTGCAJCkQmj5Sg96WmUQTiJSFpKqKdkej%2BRMXMJ8Htl0ODHnpYEy8EeV9%2FoAYng7TocnYmiLmOqBlJt2U%2BU3%2FajWt1muD2qLVpArOUn2kgtzHyauGs%2Fn7x1BxhKxIO7w9GvrcqxGkAvzRXDxVFng8TIWfkJ52jWT8TepTNrapJn%2BD1z4OjCISZ1qHUE93%2F9Rdlhykx9oOyQbyz12C10UOcvJt1eXkEBgCgO1XXCj8%2BCMlYZMzYWE0etBjulXEkb2mAFg7l7vI5nmNrHYEmaCHKuJzpwWFRwv7DW9UpGpcpntK%2FaeT4npHci2dEIPw6lW30mhBTvSL099Xb5Mj66Nm%2Fn%2B0QerrOS4%2FMuf2tkfdk4bgSPN5K8Px7dtKEV6kUqRHJt%2BJ55p11rys4taJ39Ppx9WEpvJIuEuT5Q8U3n55i8CCSR5dou25HBaUiChWjUDg036dBebNvg6MowXs1BIXYORKtoaDLDBdn%2BU2NsEuQZwHjdY4b6IiOYVlEBADQ6ILE0vuCHGo921oljV7F%2BqHiCrUU0fxdh6CNRYqz%2ByI8vYQGdrkp%2FIZ7E4vcYkeycBJE3PlD3Pp8UQgnIFy7RJszTzDaosGqVZsWMPrRwswGOqUBeOlJTFURLmcj83RE3il6IdwMYzxLq%2Fqbno%2FVqqBhzOYm2oLRXshVlVnVm2uzo2PXRjb%2FGx4zzfP%2FAft9QAyAU3MEOdCnln7zzmMh%2B44kpEPJUMqT8YKlz47ZBlWwJXp6o%2FBWDqmFELKWwP5DskznRDGvArZvhuScgEYcLbdBOpLHSBGJKSMbc8UmHe2SCfwCi5f1zs38fiKWjNa1kK14X%2BuhLKb6&X-Amz-Signature=ee613caded7d54bf2b9e9fabbbe095e4b9c5a03ae849cc14e3249aa3d799b749&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) If you want to read similar deep dives on my blog, check out these articles: ![](https://prod-files-secure.s3.us-west-2.amazonaws.com/871f1661-80b8-4d0c-ac3b-2adfc6ff4c66/5179be4a-ed9c-4e64-8833-632c1fc31665/Rack-2.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664XPPXNUZ%2F20260214%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260214T174427Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEEaCXVzLXdlc3QtMiJHMEUCIQDIcc3gAtgo1WiplVklsjSP2sgq8lBeXtAkxi98%2BwBtuwIgO7pc6ZDU1N3DYzNJWfiAuUDjIfUZhgUsqtezIrZHmTUq%2FwMIChAAGgw2Mzc0MjMxODM4MDUiDJsTRLoOVr%2FAa3oVJyrcA0hQjb%2B2409jzDcaqhxLsRfPs4cTGCAJCkQmj5Sg96WmUQTiJSFpKqKdkej%2BRMXMJ8Htl0ODHnpYEy8EeV9%2FoAYng7TocnYmiLmOqBlJt2U%2BU3%2FajWt1muD2qLVpArOUn2kgtzHyauGs%2Fn7x1BxhKxIO7w9GvrcqxGkAvzRXDxVFng8TIWfkJ52jWT8TepTNrapJn%2BD1z4OjCISZ1qHUE93%2F9Rdlhykx9oOyQbyz12C10UOcvJt1eXkEBgCgO1XXCj8%2BCMlYZMzYWE0etBjulXEkb2mAFg7l7vI5nmNrHYEmaCHKuJzpwWFRwv7DW9UpGpcpntK%2FaeT4npHci2dEIPw6lW30mhBTvSL099Xb5Mj66Nm%2Fn%2B0QerrOS4%2FMuf2tkfdk4bgSPN5K8Px7dtKEV6kUqRHJt%2BJ55p11rys4taJ39Ppx9WEpvJIuEuT5Q8U3n55i8CCSR5dou25HBaUiChWjUDg036dBebNvg6MowXs1BIXYORKtoaDLDBdn%2BU2NsEuQZwHjdY4b6IiOYVlEBADQ6ILE0vuCHGo921oljV7F%2BqHiCrUU0fxdh6CNRYqz%2ByI8vYQGdrkp%2FIZ7E4vcYkeycBJE3PlD3Pp8UQgnIFy7RJszTzDaosGqVZsWMPrRwswGOqUBeOlJTFURLmcj83RE3il6IdwMYzxLq%2Fqbno%2FVqqBhzOYm2oLRXshVlVnVm2uzo2PXRjb%2FGx4zzfP%2FAft9QAyAU3MEOdCnln7zzmMh%2B44kpEPJUMqT8YKlz47ZBlWwJXp6o%2FBWDqmFELKWwP5DskznRDGvArZvhuScgEYcLbdBOpLHSBGJKSMbc8UmHe2SCfwCi5f1zs38fiKWjNa1kK14X%2BuhLKb6&X-Amz-Signature=fb1afcafbaf2e0359ffb6ac336d06baae4f59f97d77043213d175ca7a1489e8d&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) ![](https://prod-files-secure.s3.us-west-2.amazonaws.com/871f1661-80b8-4d0c-ac3b-2adfc6ff4c66/f53b8e5d-f81c-4145-b203-b70aa5358323/auth_token-1.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664XPPXNUZ%2F20260214%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260214T174427Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEEaCXVzLXdlc3QtMiJHMEUCIQDIcc3gAtgo1WiplVklsjSP2sgq8lBeXtAkxi98%2BwBtuwIgO7pc6ZDU1N3DYzNJWfiAuUDjIfUZhgUsqtezIrZHmTUq%2FwMIChAAGgw2Mzc0MjMxODM4MDUiDJsTRLoOVr%2FAa3oVJyrcA0hQjb%2B2409jzDcaqhxLsRfPs4cTGCAJCkQmj5Sg96WmUQTiJSFpKqKdkej%2BRMXMJ8Htl0ODHnpYEy8EeV9%2FoAYng7TocnYmiLmOqBlJt2U%2BU3%2FajWt1muD2qLVpArOUn2kgtzHyauGs%2Fn7x1BxhKxIO7w9GvrcqxGkAvzRXDxVFng8TIWfkJ52jWT8TepTNrapJn%2BD1z4OjCISZ1qHUE93%2F9Rdlhykx9oOyQbyz12C10UOcvJt1eXkEBgCgO1XXCj8%2BCMlYZMzYWE0etBjulXEkb2mAFg7l7vI5nmNrHYEmaCHKuJzpwWFRwv7DW9UpGpcpntK%2FaeT4npHci2dEIPw6lW30mhBTvSL099Xb5Mj66Nm%2Fn%2B0QerrOS4%2FMuf2tkfdk4bgSPN5K8Px7dtKEV6kUqRHJt%2BJ55p11rys4taJ39Ppx9WEpvJIuEuT5Q8U3n55i8CCSR5dou25HBaUiChWjUDg036dBebNvg6MowXs1BIXYORKtoaDLDBdn%2BU2NsEuQZwHjdY4b6IiOYVlEBADQ6ILE0vuCHGo921oljV7F%2BqHiCrUU0fxdh6CNRYqz%2ByI8vYQGdrkp%2FIZ7E4vcYkeycBJE3PlD3Pp8UQgnIFy7RJszTzDaosGqVZsWMPrRwswGOqUBeOlJTFURLmcj83RE3il6IdwMYzxLq%2Fqbno%2FVqqBhzOYm2oLRXshVlVnVm2uzo2PXRjb%2FGx4zzfP%2FAft9QAyAU3MEOdCnln7zzmMh%2B44kpEPJUMqT8YKlz47ZBlWwJXp6o%2FBWDqmFELKWwP5DskznRDGvArZvhuScgEYcLbdBOpLHSBGJKSMbc8UmHe2SCfwCi5f1zs38fiKWjNa1kK14X%2BuhLKb6&X-Amz-Signature=14593f35f7070dd283a4f7990ead4b7de128981f43c34c63414ab143b9b49955&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) As always, if you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I look forward to hearing from you. If you'd like to receive future articles directly in your email, please subscribe to my blog. If you're already a subscriber, thank you.

Visibility

Visible to everyone

Reading Status

Related Bookmarks

My Note


Saved!

Annotations

Export as Markdown
+ Annotate selection

Add Annotation