Using Value Object as an ActiveRecord Attribute

Two weeks ago, I was working on a simple task, to add a query param for embed url. This embed url is actually url of content page from the main service, which I also contribute to. So I am very familiar with its url's pattern and the way it works. While my task was just to add a query param, I found a that I had to add it to 2 different classes. The good engineer part of me believed that it is an unnecessary redundancy, and something, somewhere should get the touch of refactoring.

Dived deeper i saw that the problem was in attempt to validate the url. These 2 classes uses almost similar but slightly different logic. One of them only needs to validate a livestreaming url, and the other needs to validate  both livestreaming and vod urls. In my first few attempts, I wrote a couple of validator classes, and I even tried to use ActiveSupport::Concern to wrap the validators. But something keep telling me, "Hey, this doesn't feel right, but that one doesn't either." "Yea, okay. But what does feel right?" Yes, you read the title correctly!

I realized that this is the job for the Value Object guy from that Domain Design Development village. Enough said, this embed url should be a Value Object. So, it should be validated using its own validation methods. My solution was initially something like this:

class EmbedUrl
  attr_reader :url

  def initialize(url)
    @url = url
  end

  def valid?
    # insert code here
  end

  def livestream?
    # insert code here
  end

  def vod?
    # insert code here
  end
end

So, now we need to create an EmbedUrl value-object for every url string to do the validation right? That was my thought also, but actually things could be better than that. Working with Rails and ActiveModel, I can have a model with attribute of EmbedUrl type and call the .valid? or .livestream? or .vod? method on that attribute directly. How to achieve that? Have you heard about ActiveRecord::Attributes::ClassMethod ?

So, basically ActiveRecord::Attributes::ClassMethod provides a mechanism to register a custom types attributes other than the typical DB-compatible data types to be used as ActiveModel attribute, and mechanism to serialize and deserialize these custom types to the typical ones. With this feature, I can pull all  the url validations into the value object instead of having them scattered in different classes. This technique can help prevent duplicate validations being written for the same problem and grouped related business logic together.

Comments

Popular posts from this blog

How to Upgrade PostgreSQL 10 Cluster to 12 in Ubuntu 20.04

Monkey Patching Vagrant LXC Issue in Ubuntu 20.04

Kafdrop: I can see you, Protobuf