Hiromu Masuda
Hiromu Masuda

Reputation: 259

What is the best way to separate common logic from Controllers

I have this logic below. Two controllers have same logic inside of their actions. common_logic1 common_logic2 common_logic3, and I want to separate the common logic but dont know HOW TO DO that.

class ServicesController < ApplicationController
  ...
  def download
    some_logic_for_services
    common_logic1
    common_logic2
    common_logic3
  end
  ...
end

class PackagesController < ApplicationController
  ...
  def download
    some_logic_for_packages
    common_logic1
    common_logic2
    common_logic3
  end
  ...
end

The first way is making method to ApplicationController and inherit it. But I think this way goes to the end of fat applicationController.

class ApplicationController < ActionController::Base
  ...
  def common_logic
    common_logic1
    common_logic2
    common_logic3
  end
  ...
end

class ServicesController < ApplicationController
  ...
  def download
    some_logic_for_services
    common_logic
  end
  ...
end

class PackagesController < ApplicationController
  ...
  def download
    some_logic_for_packages
    common_logic
  end
  ...
end

The second way is to separate the logic to helper module and include it. But I think helper is for separating logic from view.

module CommonHelper
  ...
  def common_logic
    common_logic1
    common_logic2
    common_logic3
  end
  ...
end

class ServicesController < ApplicationController
  include CommonHelper
  ...
  def download
    some_logic_for_services
    common_logic
  end
  ...
end

class PackagesController < ApplicationController
  include CommonHelper
  ...
  def download
    some_logic_for_packages
    common_logic
  end
  ...
end

The third way to separate logic to ActiveSupport::Concern, and I think this choice is the best in this case.

module Commonable
  extend ActiveSupport::Concern
  ...
  def common_logic
    common_logic1
    common_logic2
    common_logic3
  end
  ...
end

class ServicesController < ApplicationController
  include Commonable
  ...
  def download
    some_logic_for_services
    common_logic
  end
  ...
end

class PackagesController < ApplicationController
  include Commonable
  ...
  def download
    some_logic_for_packages
    common_logic
  end
  ...
end

Can someone tell me the pros and cons of these three methods. or if any better way to solve, plese teach me. Thank you.

Upvotes: 2

Views: 705

Answers (1)

Alex Kojin
Alex Kojin

Reputation: 5204

The Rails way is ActiveSupport::Concern. You can too include it to ApplicationController.

In some cases you can use Service way - if your logic does one thing you can move it to separate class. For example, we have shared code that check user's balance and notifies if it's negative.

If prefer to keep all services in app/services folder, that need to add to autoload_path in application.rb

config.autoload_paths += %W(#{config.root}/lib #{config.root}/app/services)

Create class CheckUserBalance

class CheckUserBalance
  def initialization(user)
    @user = user
  end

  def call
    unless @user.balance < 0
      #notify about negative balance and change user's status
    end
  end
end

In controllers, we call this service.

CheckUserBalance.new(current_user).call

Upvotes: 1

Related Questions