loading...

Design Patterns with Ruby on Rails part 1: Introduction and Policy Object

renatamarques97 profile image Renata Marques ・3 min read

This post is the first part of a series of posts about design patterns with Ruby on Rails.
See other parts here:
Part 2

What are design patterns?

A pattern is the formalization of a problem/solution pair, used to make an object-oriented design decision.
In sum, patterns are a set of general rules to achieve something that is easily repeatable for other developers.

Why design patterns are important?

First, the purpose of a pattern is to codify existing design knowledge so that developers are not constantly reinventing the wheel.
Second, design patterns make communication between designers more efficient.
Untested fat models, controllers, helpers, and views are a technical disaster, if you are not testing your code, it’s harder to see the need for using patterns.
And how can you obtain design patterns benefits? applying these concepts:

  • Isolation: if the logic related to database queries is isolated then you can easily use stubs testing. The same rule applies to stuff like indexing or the 3rd part code.
  • Readability: you can say what the given code is doing in general only by looking at the class name
  • Extendability: it’s easy to modify the existing code and there is no need to change the logic in many places.
  • Single Responsibility: a method has to be responsible only for one action.
  • Testability: thanks for the benefits mentioned, it becomes easier because we have to test only a small portion instead of large methods, connect to the external services and do the business logic at the same time.

Policy Object

Let’s begin with the simplest pattern, policy object is a pattern to deal with permissions, roles
and policies, you can use each time you have to check if something or someone is allowed to do the
action.

Naming

The filename usually has _policy suffix applied and the class with Policy at
the end, with meaningful names. The method names always end with ? character.
e.g.: RolesPolicy#admin?

If you want to have a pure policy object, stick with these rules:

  • the return has to be a boolean value
  • the logic has to be simple
  • inside the method, we should only call methods on the passed objects

e.g.:

class UsersPolicy
 def initialize(user)
 @user = user
 end

 def admin?
 confirmed? && @user.role == admin
 end

 def confirmed?
 @user.email.present? && @user.confirmed_at.present?
 end
end

Simply calling other methods and comparing using the data, this is the main purpose of policy object.
They are light, simple pure Ruby objects, used for managing permissions across the whole app.
They are also easy to test and a perfect replacement for complex conditions.

An example of a complex condition:

class PostsController < ApplicationController
 def create
 if @blog.mode == live && @blog.redactors.size > 0
 && (current_user.role == admin ||
 (current_user.role == moderator && current_user.verified_email))
 # create
 end
 end
end

The above condition checks are long, ugly, and unreadable, the policy object pattern can be applied.

Let’s begin creating PostsCreationPolicy

class PostsCreationPolicy
 attr_reader :user, :blog

 def initialize(user, blog)
 @user = user
 @blog = blog
 end

 def self.create?(user, blog)
 new(user, blog).create?
 end

 def create?
 live_blog_with_redactors? && user_with_suitable_role?
 end

 private

 def live_blog_with_redactors?
 blog.mode == live && blog.redactors.size > 0
 end

 def user_with_suitable_role?
 admin_role? || moderator_user_with_verified_email?
 end

 def admin_user?
 user.role == admin
 end

 def moderator_user_with_verified_email?
 user.role == moderator` && user.verified_email
 end
end

our controller with the policy object looks like this:

class PostsController < ApplicationController
 def create
 if PostsCreationPolicy.create?(current_user, @blog)
 #create
 end
 end
end

Policies in models

Another way of refactoring complex queries is by creating small policy methods on the model class:

class User < ActiveRecord::Base
 def admin?
 role == admin
 end

 def moderator?
 role == moderator
 end

 def authorable?
 return true if admin?

 moderator? && verified_email
 end
end
class Blog < ActiveRecord::Base
 def live?
 mode == live
 end

 def any_redactors?
 redactors.any?
 end

 def publishable?
 live? && any_redactors?
 end
end

now we can refactor our controller:

class PostsController < ApplicationController
 def create
 if @blog.published? && current_user.authorable?
 # create
 end
 end
end

As you can see, it’s a much smaller and readable way to write the same logic.

Conclusion

The policy pattern is a small concept that gives big results. Each time you have to deal with
complex conditions, think about the policy object. When it comes to testing with RSpec, you don’t
need to use database records, your policies are pure-ruby objects and your tests are going to be
very fast.

References

[book] Rails Patterns by Pawel Dabrowski

Posted on Jun 22 by:

renatamarques97 profile

Renata Marques

@renatamarques97

Computer Scientist | Back-End Developer at Codeminer42 | Open Source Enthusiast

Discussion

markdown guide
 

Great read.

The Pundit authorization gem that made this pattern very popular in the community: github.com/varvet/pundit and is a great option for authorization in your Rails project.