Reputation: 8588
I am at the point where the controller of my Rails 5 application start to get crowded, so I am thinking about moving as much as possible out to service classes. This works well for most of the business logic, but I can't seem to be able to move any instance variables out of the method. What I want to do is something that follows this pattern:
# users_controller.rb
class UsersController < ApplicationController
def show
UserService.new.set_user_detail_variables(params[:id])
respond_to do |format|
format.html
format.json { render json: @user }
end
end
end
# user_service.rb
class UserService
def set_user_detail_variables(user_id)
@user = User.find(user_id)
@cars = Car.where(brand: 'Volvo')
end
end
Is it all possible to move instance variables out of the controller?
Upvotes: 2
Views: 1466
Reputation: 2401
UPDATED according to your updated question
I believe you have to have at least one instance variable in your controller action to render its data or send it as json
. And service object are not the one to do such things. Service objects designed to perform single huge or complicated operation.
What you could do is to use Presenter object (Presenter pattern as Rails community sees it). This pattern in Rails is useful to "hide" several instance variables inside the single one. So put your instance variables inside the single Presenter variable. Then pass presenter to the views or render its data as json
.
Example
Before:
class UsersController < ApplicationController
def show
@user = User.find(user_id)
@cars = Car.where(brand: 'Volvo')
respond_to do |format|
format.html
format.json { render json: @user, @car }
end
end
end
After:
class UsersController < ApplicationController
def show
user = User.find(user_id)
cars = Car.where(brand: 'Volvo')
@show_presenter = ShowPresenter.new(user, cars)
respond_to do |format|
format.html
format.json { render json: @show_presenter }
end
end
end
class ShowPresenter
def initialize(user, cars)
@user = user
@cars = cars
end
end
Upvotes: 1
Reputation: 4920
If you want to do some calculations in a separate method and assign some instance variables there, then use them in your view, you can move those methods to a mixin and include that mixin inside your controller.
# mixins/user_helper.rb
module UserHelper
def set_user_detail_variables(user_id)
@user = User.includes(:comments, :addresses, :posts).find(user_id)
@user_comments = @user.comments
@user_addresses = @user.addresses
@user_posts = @user.posts
end
end
# controllers/users_controller.rb
class UsersController < ApplicationController
include UserHelper
def show
set_user_detail_variables(params[:id])
respond_to do |format|
format.html
format.json { render json: @user }
end
end
end
This way your controller would not get lengthy and also you will be able to use your variables.
Upvotes: 2