Refactoring Rails Controllers with Interactors: More Clarity, Less Coupling
In a recent Ruby on Rails project, I came across controllers overloaded with responsibilities: business logic, validations, side effects, and conditionals all mixed together.
It made testing hard, onboarding slower, and changes risky.
To improve this, I proposed and implemented a transition to Interactors, focusing on single responsibility and step composition.
The Impact
- Controllers became lean and predictable
- Business logic was isolated, reusable, and easy to test
- Team onboarding improved with clearer structure
- Reduced risk of regression in deployments
Before
class UsersController < ApplicationController
def create
user = User.new(user_params)
if user.save
EmailConfirmationService.send_confirmation(user)
Analytics.track("user_created", user_id: user.id)
redirect_to root_path, notice: "Account created. Please check your email."
else
flash[:error] = user.errors.full_messages.to_sentence
render :new
end
end
private
def user_params
params.require(:user).permit(:email, :password, :name)
end
end
After:
class UsersController < ApplicationController
def create
result = CreateUser.call(params: user_params)
return redirect_to root_path, notice: "Account created. Please check your email." if result.success?
flash[:error] = result.error
render :new
end
private
def user_params
params.require(:user).permit(:email, :password, :name)
end
end
# app/interactors/create_user.rb
class CreateUser
include Interactor
def call
user = User.new(context.params)
if user.save
EmailConfirmationService.send_confirmation(user)
Analytics.track("user_created", user_id: user.id)
context.user = user
else
context.fail!(error: user.errors.full_messages.to_sentence)
end
end
end
Final Thoughts
Refactoring isn’t just about writing cleaner code — it’s about building systems that are easier to understand, test, and evolve.
In my experience, introducing Interactors in legacy or monolithic Rails apps has been a reliable way to regain control over complexity while improving the development experience for everyone on the team.
Tags
#RubyOnRails #Interactor #Refactoring #SoftwareEngineering #CleanCode #BackendDevelopment