Putting presentation logic in controller is a good practice in Ruby?
You are not the first to wonder this. If views and controllers should have little to no logic, and the model should be presentation agnostic, where does presentation logic belong?
Turns out we can use an old technique called the decorator pattern. The idea is to wrap your model object with another class that contains your presentation logic. This wrapper class is called the decorator. The decorator abstracts away logic from your view, while keeping your models isolated from their presentation.
Draper is an excellent gem that helps define decorators.
The sample code you gave could be abstracted like so:
Pass a decorator to the view with @user = UserDecorator.new current_user
in your controller.
Your decorator could look as below.
class UserDecorator decorates :user def welcome_message if user.admin? "Welcome back, boss" else "Welcome, #{user.first_name}" end endend
And your view would simply contain @user.welcome_message
Notice that the model itself doesn't contain the logic to create the messages. Instead, the decorator wraps the model and translates model data into a presentable form.
Hope this helps!
I would use a helper for this. Suppose you have to translate the welcome-message, based on some locale.
In the app/helper/user_helper.rb
write
module UserHelper def welcome_message(user) if user.admin? I18n.t("admin_welcome_message", :name => user.name) else I18n.t("user_welcome_message", :name => user.name) end end end
and in your view you can then just write
<%= welcome_message(user) %>
Note that the decorator/presenter offers a really clean object-oriented approach, but imho using a helper is much simpler and sufficient.
No, you don't want any conditionals at all in the user class nor the controller. The point of that example on the blog post is to make reference to polymorphism, just good old fashioned OO design.
# in application_controller for exampledef current_user if signed_in? User.find(session[:user_id]) else Guest.new end end#app/models/user.rbclass User def welcome_message "hello #{name}" endend#app/models/guest.rbclass Guest def welcome_message "welcome newcomer" endend
...you get the idea.
Only, instead of littering your model with presentation-only methods, create a decorator that acts as a presenter:
require 'delegate'class UserPresenter < SimpleDelegator def welcome_message "hello #{name}" endend
And now current_user
looks like so:
# application_controllerdef current_user if signed_in? UserPresenter.new(User.find(session[:user_id])) else Guest.new endend