Ognjen Regoje bio photo

Ognjen Regoje
But you can call me Oggy


I make things that run on the web (mostly).
More ABOUT me and my PROJECTS.

me@ognjen.io LinkedIn

ActorModel pattern in Rails

#architecture #pattern #technical

Something I’ve been using that I’ve referred to as ActorModels. Not sure if I’ve seen it documented elsewhere.

Basically, it’s subclassing a model based on who’s using it and keeping the original model as slim as possible.

For instance a Product model might look like this:

class Product < ActiveRecord::Base
  has_many :variations, dependent: :destroy
  scope :published, -> {where(published: true)}
  ...

It contains the the information that either describes the model or is common to all subclasses but anything specific to a user type is in an “ActorModel” that inherits from it.

So, there might be a product for admins:

class Admin::Product < Product
  # This scope is only useful within admin's context. For everyone else this might not matter.
  scope :live_before, -> (date) {where("date(products.published_on) < ?", date)}
  # has_many using an ActorModel for QualityIssues
  has_many :quality_issues, class_name: "Admin::QualityIssues"
end

Or for buyers:

class Buyer::Product < Product
  # Others might not use elastic for search
  include ProductSearchable

  # The admin doesn't need recommendations, the buyer does.
  has_many :recommendations
end

Or for suppliers:

class Supplier::Product < Product
  # They're the same issues as the admin but have different ActorModel
  has_many :quality_issues, class_name: "Supplier::QualityIssues"
end

And finally for internal usage:

class Internal::Product < Product
  # None of the users actually need these.
  def self.index(id)
    ...
  end

  def to_index_json
    ...
  end
end

The main benefit is of course that the large models that are used throughout end up being much smaller therefore much more readable, much easier to find what it is you’re looking for.

The main downside is that sometimes functionality might end up being duplicated but I haven’t found it to be that big of an issue so far.

In particular I’ve found this pattern to be useful for Products, Orders and Companies.

Company is a particularly interesting one because it’s got a few different perspectives: own account, buyer, supplier, and then for admin buyer and supplier as well.