views:

925

answers:

4

I don't understand why one method would work and the other would throw a NoMethodError if they come from the same lib file.

# app/views/bunnies/show.html.erb
<% if logged_in? %>
  <%= current_user.login %> |
  <%= link_to 'Logout', logout_path %> |
  <% if authorized? %>
    <%= link_to 'Edit Details', edit_bunny_path(@broker) %> |
  <% end %>
  <%= link_to 'Back', bunnies_path %>
<% end %>

... throws a NoMethodError for authorized?. If I comment that if block out, the page works fine (with logged_in?).

# lib/authenticated_system.rb
def logged_in?
  !!current_user
end

def authorized?
  current_user.login == "admin"
end

# app/controllers/application.rb
class ApplicationController < ActionController::Base
  include AuthenticatedSystem
end

What gives?

A: 

Right, so I still don't understand why that wasn't working, but I have found an alternative solution.

(1) Leave authenticated_system.rb as is.

(2) Add a helper method to controllers/application.rb:

helper_method :is_admin?
def is_admin?
  if logged_in? && current_user.login == "admin"
    true
  else
    false
  end
end

(3) Use the helper method instead of authorized?. If anyone would like to explain why the original code wasn't working, I'm all ears!

(Thanks to this post)

neezer
+2  A: 

I'm guessing you are not logged in when the error is thrown. The NoMethod is not referring to #authorized?. It is actually referring to the #login method of current_user. If you aren't logged in, then current_user is nil, resulting in NoMethod when current_user.login is called within #authorized?.

Any helper like authorized? that checks user status should include checking logged_in? first to bypass this problem. Try this...

def authorized?
  logged_in? and current_user.login == "admin"
end

That way you bounce out of the conditional if not logged in, and you don't try to access #login method unless you actually have an object available.

You might also look into some of the available role-based authentication schemes that work with Restful_Authentication. If your access patterns are going to be any more complex than just checking for an admin, then it will be easier to use one of those plugins.

Incidentally, farther down in authenticated_system.rb you will find this code:

# Inclusion hook to make #current_user and #logged_in?
# available as ActionView helper methods.
def self.included(base)
  base.send :helper_method, :current_user, :logged_in?, :authorized? if base.respond_to? :helper_method
end

This is what makes methods in this module available as helper methods in the views. If you add a method to authenticated_system.rb that returns user status (for instance, something like #superuser?), you will need to add that method symbol to the base.send call in this code. Again, if you find yourself writing a lot of code for access control, learning one of the plugins would be in order.

Yardboy
Thanks - for the moment, my user setup is pretty simple, but it will grow. Are there any plug-ins in particular you recommend?
neezer
If all you need is admin check then your golden with RA. The trouble with the rbac plugins is they all work but none of them do everything you want. I think that the Role Requirement plugin is a good one to start with (http://code.google.com/p/rolerequirement/), and a good one to learn from.
Yardboy
your s/b you're. ;) Hate typos.
Yardboy
+1  A: 
def is_admin?
  logged_in? && current_user.login == "admin"
end

is enough

A: 

Nevermind, retracted :) Already answered.

Tony Collen