Question

Some recommendation [1] suggest you to use

<%= current_user.welcome_message %>

instead of

<% if current_user.admin? %>
  <%= current_user.admin_welcome_message %>
<% else %>
  <%= current_user.user_welcome_message %>
<% end %>

But the problem is you must have the decision logic somewhere in your code.

My understanding is putting the decision in template is better than controller as it make your controller more clean. Is it correct?

Are there better way to handle this?

http://robots.thoughtbot.com/post/27572137956/tell-dont-ask

Was it helpful?

Solution

In my opinion, if the text is the only thing that changes, it doesn't belong in a view. If you needed to restructure the page, that's presentation logic. This, this is just data being different.

OTHER TIPS

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
  end
end

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 example
def current_user
  if signed_in?
    User.find(session[:user_id])
  else
    Guest.new
  end  
end

#app/models/user.rb
class User
   def welcome_message
     "hello #{name}"
   end
end

#app/models/guest.rb
class Guest
  def welcome_message
    "welcome newcomer"
  end
end

...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}"
  end
end

And now current_user looks like so:

# application_controller
def current_user
  if signed_in?
    UserPresenter.new(User.find(session[:user_id]))
  else
    Guest.new
  end
end

Decorate the user model and add the welcome_message to it directly. Yes, this may involve some kind of conditional statement at some point.

http://robots.thoughtbot.com/post/14825364877/evaluating-alternative-decorator-implementations-in

I think you should watch the railscasts episode on Presenters for the answer.

Logic in the view is hard to maintain, we should put the business logic in the model and all view logic in helpers.

If you want your code to be in Object Oriented fashion, make use of Decorators (object oriented way of helpers)

Best Example : https://github.com/jcasimir/draper

Put the code defining current_user.welcome_message in _app/helpers/application_helper.rb_, it will then be accessible by any view rendered with the application layout.

Another option is to define a custom helper module, one which is not necessarily associated with a given view or controller (See the video I linked below), and include it in the modules of the view/controllers you wish to have that functionality in.

This is not something that is black and white. But, from what you have described it sounds like this is code that is obtrusive to stick in your application_controller.rb and it is not code with functionality which justifies it's own controller, the most effective and efficient option may be to create a custom helper module and include it in the helpers you wish to have that functionality. That said, this is ultimately a judgement call which the designer of the application (i.e. you) needs to decide upon.

Here is a good article outlining helper modules from May, 2011

Here is is a RailsCast outlining custom helper modules (i.e. custom as in modules not necessarily associated with a given controller or view). Short, sweet, and to the point.

You can define helper method for that stuff. I don't think it is a good Idea to make a welcome sentences in a model, but in the controller too. But you should try to make you views clean from code, and if you can use helpers for that then you should to.

A good practice would be to have real View instances. Rails parody of MVP (there is difference, look it up) unfortunately seems to pretend that views are templates. That is wrong.

Views are supposed to contain the presentation logic in MVC and MVC-inspired patterns. They are also supposed to manipulate multiple templates and make decision on which templates to employ to represent the state and information from the model layer (yes, model is a layer not an ORM instance).

So, to answer the question: presentation logic has no place in controllers.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top