Hanami, Why?: Model Citizens
Welcome to the latest installment of my Hanami, Why? series. In case you've missed it, I recommend reading Hanami, Why?: Class Action before diving into this one. Today, we will be focusing on Hanami's database layer. It's worth noting that Hanami doesn't have a traditional model layer like Rails does. As always, this series will provide a high-level introduction followed by a deep dive into the reasons behind the current state of things.
Please bear in mind that I am still learning about Hanami's database layer myself, and Adam Lassek is constantly surprising me with new tidbits of information.
Hanami's database layer consists of three primary components: Relations, Repos, and Structs. Relations are where you define an object's schema and relationships to other objects, as well as where you can define scopes or datasets. Repos represent the repository pattern and are optional in Hanami, but using them is highly encouraged due to their ability to operate on multiple relations. Lastly, Structs are simple, frozen representations of your objects, used for defining presentation logic.
To demonstrate Hanami's database layer, let's consider a scenario with a schema migration. I won't go into detail about migrations, as this topic is well covered in the Hanami documentation. Instead, I'll show you an example of a users table and a Relation based on it. We also have a UserRepo with methods to find and create users, and a User struct with presentation logic methods.
Imagine a situation where Product decides that using created_at to determine the freshness of an issue is no longer effective. Instead, they want to use a new field called fresh_status, which is updated by a background job every hour. Manually updating all the call sites for this change would be a nightmare. This is where the repository pattern shines. By moving this logic into a Repo, you can ensure that only one place in your codebase knows about the change, making future modifications much easier.
Here's an example of how the freshness logic could be implemented in Hanami's database layer. The action asks for the repo and calls it, keeping the rest of your application blissfully unaware of the changes. By using this approach, you maintain the single source of truth for the functionality, just like the FreshnessController example.
Ultimately, Hanami's database layer, with its Relations, Repos, and Structs, provides a clean and maintainable way to work with your data. By leveraging the repository pattern, you can avoid the pitfalls of ActiveRecord and keep your codebase organized and easy to understand.
Written by urgent.news from Lobsters's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.