Posted by
ihower
on
July 24, 2010
According to MVC architecture, there should not be logic codes in view, in this practice, I will introduce you to move codes into model.
Bad Smell
<% if current_user && (current_user == @post.user ||
@post.editors.include?(current_user)) %>
<%= link_to 'Edit this post', edit_post_url(@post) %>
<% end %>
In this example, we check the edit permission in view with a complex code, but complex logic codes should not be placed in view, we should move it to model.
Refactor
<% if @post.editable_by?(current_user)) %>
<%= link_to 'Edit this post', edit_post_url(@post) %>
<% end %>
class Post < ActiveRecord::Base
def editable_by?(user)
user && (user == self.user || self.editors.include?(user))
end
end
Now it's clear that we move the permission logic into editable_by? method in model, that makes the view code more readable and we can easily reuse the editable_by? logic in other view files.

Comments
<%= link_if_editable(@post) %>
@steved we have a serial posts about moving logic codes from view to model, controller and helper. It depends on why the logic codes should be.
# config/initializers/active_record.rb
class ActiveRecord::Base
attr_accessor :current_login_user
end
# controller (maybe should be placed inside application controller, or a mixin or a 3rd party declarative)
class PostController < ApplicationController
def show
@post.current_login_user = current_user
end
end
# model
class Post < ActiveRecord::Base
def editable?
[self.user, self.editors].flatten.include?(current_login_user)
end
end
# view
<% if @post.editable? %>
...
<% end %>
def editable?
[user, editors].flatten.include? User.current_user
end
You do have to keep in mind that User.current_user might be nil (in the case of a rake task, console, cron job, etc.) but I have found it to be a great way of letting my permissions stay in the models.