Rails Best Practice: Keep model logic in models or concerns

Signs

The general sign is to watch for the repetitive appearance of one or more variables inside one particular controller action. In the example below, the account variable appears 6 times in one action which indicates that whatever logic it is doing should not belong in this controller.

The common mistake a new or mid-level developer often make is the tendency of moving the repetitive code into the model immediately, not seeing where it truly belongs first. They can belong to a Concern, Service, Presenter, etc… We think that we are organizing code, but it’s only sweeping under the carpet and causing much maintenance work later on when the models getting bigger in size.

In this case, we also see the ‘subject’ variable user is calling accounts.... Further investigation shows that user be of an restaurant_owner or a consumer, therefore, this code should belong to both of these models; and that indicates that it should belong to a Rails Concern (other cases may indicate the code should be moved into a Service)

Before

def create
@account = @user.accounts.first
if !@account
@account = @user.accounts.new( account_save_params )
elsif !@account.accessible
@account.attributes = account_save_params
end
  if @account.save
render ‘show’
else
render json: { error: “Account Data Invalid” }, status: :unprocessable_entity
end
end

And after!

def create
@account = @user.build_or_update_account(account_save_params)
if @account.save
render :show
else
render json: { error: ‘Account Data Invalid’ }, status: :unprocessable_entity
end
end

The created concern:

module Accountable
extend ActiveSupport::Concern
  def build_or_update_account(account_save_params)
account ||= Account.new(account_save_params)
account.attributes = account_save_params unless account.accessible
account
end
end

It feels good to see your things clean and organized, doesn’t it? What are you waiting for, let’s give your much loved code a clean-up job today!

A little clean-up and organizing goes a long way.