Thursday, May 9, 2024
HomeRuby On RailsRepository implementation on ActiveRecord | Arkency Weblog

Repository implementation on ActiveRecord | Arkency Weblog


In its essence, a Repository separates area objects from how they’re persevered and gives a restricted interface to entry them. It’s a tactical sample described with much more phrases by Fowler and Evans than I’d like to incorporate on this introduction.
It stands in full opposition to what ActiveRecord sample promotes. Why hassle remodeling one into one other?

The issue with ActiveRecord sample comes from its biggest energy. It’s a double-edged sword. Immensely helpful in fast prototyping for a “solopreneur”. Versatile for a well-knit and disciplined group. Spiralling uncontrolled in a large organisation with a number of groups engaged on a comparatively large legacy software.

As of now naked ActiveRecord::Base begins with 350 occasion strategies on its public interface. Add to that 496 strategies of ActiveRecord::Relation that one normally interacts with. Performing a bigger refactoring that covers all doable utilization patterns of such ActiveRecord fashions turns into a nightmare. Preliminary guidelines consists of:

  • huge question API
  • callbacks
  • relations, its extensions and the standard behaviour
  • gems within the Gemfile that reach ActiveRecord::Base — including new strategies and altering behaviours

That’s a big scope to cowl. It interprets to a sure price of time, vitality and confidence to tug out any change on it in a manufacturing system that earns cash.

I keep in mind just a few previous makes an attempt from my colleagues to regulate the scope of ActiveRecord surfaced in bigger codebases.
There was the not_activerecord to assist specific the boundaries. There have been numerous approaches to question objects that addressed the learn half.

I additionally vaguely recall a quote from Adam Pohorecki on a DRUG meetup that you may get 80% advantages out of Repository by placing 20% effort into shaping ActiveRecord like this:

class Transaction
  def self.of_id(id)
    discover(id)
  finish

  def self.last_not_pending_of_user_id(user_id)
    the place.not(standing: "pending").the place(user_id: user_id).order(:id).final
  finish
finish

It depends very a lot on the self-discipline of group — to deal with ActiveRecord::Base strategies as “non-public” and solely entry the mannequin by the application-specific class strategies.

This the repository I’d make in the present day, with none exterior dependencies within the framework you have already got:

class TransactionRepository
  class File < ActiveRecord::Base
    self.table_name = "transactions"
  finish
  private_constant :File

  Transaction = Information.outline(File.attribute_names.map(&:to_sym))

  class << self
    def of_id(id)
      as_struct(File.discover(id))
    finish

    def last_not_pending_of_user_id(user_id)
      as_struct(File.the place.not(standing: "pending").the place(user_id: user_id).order(:id).final)
    finish

    non-public

    def as_struct(file)
      Transaction.new(**file.attributes.symbolize_keys)
    finish
  finish
finish

Let’s dissect this pattern a bit.

  1. TransactionRepository and its public strategies kind the API. Because it takes no dependencies and carries no state inside its lifecycle, the strategies are on the singleton. These are the one methods to entry the information and the floor could be very restricted.
  2. TransactionRepository::File is the ActiveRecord class. We have now to level to its database desk with self.table_name, since its namespace is “unconventional” to the framework mechanics. We might use File inside the repository and to implement its performance. This fixed just isn’t accessible exterior the repository — encapsulation is fulfilled.
  3. Return values of repository queries are immutable structs. They’re not ActiveRecord::Relation. They’re not ActiveRecord::Base cases both.

Does this strategy have drawbacks? It actually does. Like all the pieces else it’s an artwork of selection. We’re buying and selling comfort off in a single space for predictability and maintainability within the different. YMMV.

The place huge ActiveRecord floor shines probably the most is the view layer and the quite a few framework helpers constructed on prime of it. We don’t get that advantages with our structs. We would get again a few of them by together with ActiveModel::Naming behaviours.

Does this strategy have any alternate options? The CQRS — a separation of write and skim fashions, the place there was beforehand one, may very well be a viable possibility for some. Provided that writes and reads are applied and optimised in a different way, the ActiveRecord matches the learn half completely. It’s my most popular car to implement Learn Mannequin on prime of denormalised SQL database tables in Rails.



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments