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)