Reputation: 2900
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
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