The Rails convention is to put your business logic should be on the models. Here’s a typical example:
app/controllers/users_controller.rb
class UsersController < ApplicationController def suspend @user = User.where(user_id: params[:id]).first @user.suspend! redirect_to @users, notice: 'Successfully suspended user!' end end
app/controllers/user.rb
class User include Mongoid::Document def suspend! update_attributes(banned: true) solutions.each { |s| s.update_attributes(hide: true) profile.update_attributes(hide: true) end end
The problem with this code is that too much logic is cluttered into a single method on the model. This makes your code harder to read and maintain.
One way to refactor your code is to break suspend! into multiple methods:
app/models/user.rb
class User include Mongoid::Document def suspend! ban_user! hide_solutions! hide_profile! end def ban_user! update_attributes(banned: true) end def hide_solutions! solutions.each { |s| s.update_attributes(hide: true) end def hide_profile! profile.update_attributes(hide: true) end end
The problem with this code is that class does too many things (too much logic inside a single class) which breaks the Single Responsibility Principle.
The best way to do this is to put the unique business logic of suspending a user on a new class ‘UserSuspension’. Take note that the new class doesn’t have to be an ActiveRecord (Mongoid Document). This class can be a PORO (Plain Old Ruby Object).
app/models/user_suspension.rb
class UserSuspension def initialize(user) @user = user end def create ban_user! hide_solutions! hide_profile! end private def ban_user! update_attributes(banned: true) end def hide_solutions! solutions.each { |s| s.update_attributes(hide: true) end def hide_profile! profile.update_attributes(hide: true) end end
The main advantage of putting this unique business logic on a PORO makes this class responsible for only one thing. It makes it easier to read and maintain your code.
Now on our controller, let’s see the PORO in action.
app/controllers/users_controller.rb
class UsersController < ApplicationController def suspend @user = User.where(user_id: params[:id]).first suspension = UserSuspension.new(@user) suspension.create! redirect_to @users, notice: 'Successfully suspended user!' end end
Using PORO helps your Rails application become more modular and easier to maintain.