mr_muscle
mr_muscle

Reputation: 2900

Rails 6 override part of the inherited controller method - DRY

I want to be in line with DRY principals that's why I'm trying to refactor my controllers. I've got BaseController as parent and ShareBuysController as child, like below:

# base_controller.rb

  class BaseController < ApplicationController
    def create
      @transaction = wallet.transactions.new(transaction_params) do |t|
        t.transaction_type = transaction_type
      end

      if @transaction.save
        success_response
      else
        failure_response
      end
    end
  end

# share_buys_controller.rb

  class ShareBuysController < BaseController
    def create
      @transaction = wallet.transactions.new(transaction_params) do |t|
        t.transaction_type = transaction_type

        # new lines of code
        t.amount = calculate_shares_amount(params[:transaction][:shares_number])
        t.to_wallet = portfolio.wallet
      end

      if @transaction.save

        # new lines of code
        recalculate_balance!
        recalculate_portfolio_balance!(@transaction)

        success_response
      else
        failure_response
      end
    end
  end 

Is there a way to add just these lines of code which I've marked by # new lines of code and everything else can stay the same? Or I have to override whole create method like I did?

Upvotes: 0

Views: 452

Answers (1)

Les Nightingill
Les Nightingill

Reputation: 6156

I would refactor much of this code into models. Along the lines of the old paradigm "fat model skinny controller". I don't know nearly enough about your app, but the kind of refactoring that might be appropriate is:

# base_controller.rb

  class BaseController < ApplicationController
    def create
      @transaction = BaseTransaction.new(wallet, transaction_params)

      if @transaction.save
        success_response
      else
        failure_response
      end
    end
  end

# share_buys_controller.rb

  class ShareBuysController < BaseController
    def create
      @transaction = ShareBuysTransaction.new(wallet, transaction_params)

      if @transaction.save
        success_response
      else
        failure_response
      end
    end
  end

# models/base_transaction.rb
class BaseTransaction < Transaction
  def initialize(wallet, params)
    self.wallet_id = wallet.id
    self.transaction_type = transaction_type
    super
  end

end

# models/share_buys_transaction.rb
class ShareBuysTransaction < Transaction
  after_save :recalc

  def initialize(wallet, params)
    self.wallet_id = wallet.id
    self.transaction_type = transaction_type
    self.amount = calculate_shares_amount(params[:transaction][:shares_number])
    self.to_wallet = portfolio.wallet
    super
  end

  def recalc
    recalculate_balance! # where is this defined? class method?
    self.recalculate_portfolio_balance!
  end
end

I'm assuming you have a Transaction model inheriting from ActiveRecord::Base.

I'm sure there's some errors in this code b/c there's much about your app I don't know, but hopefully you can see the picture and make it work. You could even have ShareBuysTransaction inherit from BaseTransaction and use super in its initialize method, to save a couple of lines.

You'll have to disable STI for the Transaction model, b/c you're not interested in that feature here. You just want inheritance of methods.

You could even eliminate create from ShareBuysController and just put before_create { @transaction=ShareBuysTransaction.new(wallet,transaction_params) and in BaseTransactionsController do before_create {@transaction=BaseTransaction.new(wallet, transaction_params). Oooh that's really DRY!

Upvotes: 1

Related Questions