DEV Community

Cover image for Command Driven Design Pattern - ROR
Samala Sumanth
Samala Sumanth

Posted on

Command Driven Design Pattern - ROR

In this blog we'll dive into one lesser-known design pattern but highly efficient for large scaled applications which helps the code repository to keep organised and can be easily scaled up.

Design Pattern Name: Command Driven Pattern

Usually the request from client goes to the controller which speaks to the model ( database ) and send back the view or JSON.

But in this design pattern request from controller goes to a command, and a command can be having number of actions items to perform and send the response back.

In layman terms take an example of constructing a shopping mall. the action items are:

  1. Buy the plot.
  2. Setting up the base.
  3. Raising the walls.
  4. Elevators
  5. Painting

so all these five steps can we performed a separate file called as COMMAND.

Lets consider this scenario:

Example: On User Sign up, consider these following actions are to be performed.

  1. User must be authenticated.
  2. User must be sent a logged-in alert email.
  3. User should be awarded some points.
  4. User should receive push notification.
  5. Audit for all the above actions.

Let's create a folder in app/ called core and file called Command.rb

class Core::Command
  include ActiveModel::Validations

  attr_accessor :token

  def initialize(attributes = {})
    attributes.each do |name, value|
      if methods.include? "#{name}=".to_sym
        method("#{name}=".to_sym).call(value)
      end
    end
  end

  # this method can be ovveridden in other classes
  def run
  end
end
Enter fullscreen mode Exit fullscreen mode

Now in Lets create CreateUserCommand.rb in core folder

class Core::CreateUserCommand < Core::Command
  attr_reader :user_params

  def initialize(params)
    super(params)
    @user_params = params
  end

  def run
    ActiveRecord::Base.transaction do
      authenticate_user
      mailer("Account Created")
      award_points
      send_push_notification
      mailer("User Logged In")
    end
    # can be written in JSON builder a seprate file
    return { name: "Samala Sumanth", git: "https://github.com/SamalaSumanth0262"}
  end

  def authenticate_user
    # can be separate command for user authentication
    puts "User Authenticated"
  end

  def mailer(message)
    # can be separate command for mailer
    puts message
  end

  def award_points
    # can be written in separate command for awarding points
    puts "User has been awarded 10 points"
  end

  def send_push_notification
    # User Notification Command
    puts "User has been sent push notification"
  end
end

Enter fullscreen mode Exit fullscreen mode

And Finally your controller should look like this

class UsersController < ApplicationController
  # bypass csrf protection for all the requests made
  protect_from_forgery with: :null_session
  before_action :set_user, only: %i[ show edit update destroy ]
  # /users/
  def create
   render json: ::Core::CreateUserCommand.new(user_params).run
  end

  private
    # Only allow a list of trusted parameters through.
    def user_params
      params.fetch(:user, {})
    end
end
Enter fullscreen mode Exit fullscreen mode

Thats It. with this approach we have moved most of the logic into command instead of having them in fatty models.

Please feel free to comment and suggest any kind of improvement.

This blog is also inspired by: https://blog.slava.dev/command-driven-architecture-for-ruby-on-rails-35949a0b0558

You can contact me from my portfolio: https://sumanthsamala.netlify.app

Top comments (0)