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:
- Buy the plot.
- Setting up the base.
- Raising the walls.
- Elevators
- 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.
- User must be authenticated.
- User must be sent a logged-in alert email.
- User should be awarded some points.
- User should receive push notification.
- 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
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
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
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
Top comments (0)