views:

222

answers:

5

I currently have code in my ApplicationController to check if a user is logged in and has the required access to perform a given action (the tests take place in a before_filter).

I require the same functionality in the views to decide if I should be showing the admin links in a list view, but how do I best avoid duplicating code in the controllers and views?

The way I have chosen to do it now, is to have the user_can_edit_customers? essentially be a wrapper for 'can_edit_customers?' on my User class:

ApplicationController:

class ApplicationController 

And then do something similar in my view helpers.

This way all functionality is encapsulated in the User model but I still need to define wrappers in my controllers and helpers, but are there smarter ways of doing this?

Note, the user stuff is only an example - this also applies to other pieces of functionality.

+3  A: 

I would say do away with the wrappers and just call *can_edit_customers?* directly on the user object passed to the view.

If you want to keep them a solution might be to use helper_method in your controller.

helper_method :current_user, :can_edit_customers?

def current_user
    @current_user ||= User.find_by_id(session[:user])
end

def can_edit_customers?
    @current_user.can_edit_customers?
end

This way the method also becomes available in the view.

<% if can_edit_customers? -%>...<% end -%>
Hates_
A: 

I think helpers are the way to do what you want. As for checking in views whether the user has or not the priviledge to do something, you could put a flag in your session data (e.g. session[:admin] = true and check that in your view.

Keltia
A: 

It is common practice to make methods like logged_in? available in the controller and the views. For most cases, you don't need to push down authorization logic into the models.

Definetly go with with the approach user Hates described. Have a look at plugins like restful_authentication and acts_as_authenticated, to see how they did it.

There are several railscasts (http://railscasts.com/episodes?search=authentication) covering this topic. For instance, you could write a helper that takes a block and is then used like this:

<%- admin_user_ do %>
  <%= link_to .. %>
  <%= link_to .. %>
  <%= link_to .. %>
<%- end %>
Kafka
+1  A: 

Just to be more direct. The helper_method "macro" in a controller causes a controller method to behave as if it's also a method in the application helper.

helper_method :current_user, :can_edit_customers?
Aaron Longwell
A: 

Personally I think you should not use helpers.

I would take a different solution.

Let's say that we have Cucumber, a model, that should not be editable by some users. I create #editable? method as follows:

class Cucumber < ActiveRecord::Base
  def editable?(current_user)
    # Something happens here.
  end
end

Note that if a page is accessible by everyone, current_user might be false.

Then, in the views you're able to do:

<%- if @cucumber.editable?(current_user) -%>
<%# Something happens here. -%>
<%- end -%>

And, in the controllers, use a filter.

The best thing about this approach is that it follows Fat Model, and enables you to easily cover your permissions with unit tests.

maurycy