KatPadi's Point

Policy Object Adventures

A few months back, I wrote something about my service object adventures to handle extraction of a business logic from a Rails model or controller. Recently, I got introduced and experimented on the concept of policy object.

Policy objects are pretty much just like service objects. In fact, from what I understand, policy object is actually a service object. The only difference is that policy objects encapsulate operations that exclusively return boolean values. It should describe only whether the subject passed the policy or not.

I recreated my very first policy implementation and structure by creating an oversimplified example here https://github.com/katpadi/adventures_in_policies.

This is the base class for my policy:

[pastacode lang=”ruby” user=”katpadi” repos=”adventures_in_policies” path_id=”voting_policy.rb” revision=”” highlight=”” lines=”” provider=”github”/]

This base class just loops through the result of the factory and checks if a “policy” is violated by the “voter”.

Here’s a simple factory implementation that builds an array of policy instances:

[pastacode lang=”ruby” user=”katpadi” repos=”adventures_in_policies” path_id=”voting_policy_factory.rb” revision=”” highlight=”” lines=”” provider=”github”/]

Basically, the factory just creates the default policy objects needed.

Here are some subclasses for the base policy class:

[pastacode lang=”ruby” user=”katpadi” repos=”adventures_in_policies” path_id=”policies/age_voting_policy.rb” revision=”” highlight=”” lines=”” provider=”github”/]

[pastacode lang=”ruby” user=”katpadi” repos=”adventures_in_policies” path_id=”policies/residency_voting_policy.rb” revision=”” highlight=”” lines=”” provider=”github”/]

[pastacode lang=”ruby” user=”katpadi” repos=”adventures_in_policies” path_id=”policies/disqualification_voting_policy.rb” revision=”” highlight=”” lines=”” provider=”github”/]

After setting it up like this, the only call that I need to do in the interface is:

[pastacode lang=”ruby” message=”” highlight=”” provider=”manual”]

# Assuming we have a voter variable that has all the voter's attributes
# voter = Voter.new('Kat Padilla', 20)

# This is the only thing that I need to do!!!
VotingPolicy.new(voter).passed?

[/pastacode]

This call will already determine if the “voter” passed all the “policies” that I included in the factory.

As a bonus fun approach, a colleague told me that it’s also better if an optional or custom policy may be passed. In the future, for instance, a random policy is needed, they don’t have to dig deeper and edit the existing codes. They just have to add a policy object and pass it in the public method.

[pastacode lang=”ruby” message=”” highlight=”” provider=”manual”]

VotingPolicy.new(voter, custom_policies: Policies::AlwaysFalsePolicy).passed?

[/pastacode]

This call will loop through all the default policies plus the custom policy passed.

I’m not sure if this is the best way to structure it but so far, I’m conveniently exercising this approach.

So, that’s it for my policy object adventures!

1 comment for “Policy Object Adventures

Leave a Reply

Your email address will not be published. Required fields are marked *