[rspec-users] Best Practice for Controllers

David Kahn dk at structuralartistry.com
Fri Jan 21 23:25:28 EST 2011


On Mon, Jan 17, 2011 at 1:43 PM, David Chelimsky <dchelimsky at gmail.com>wrote:

> On Jan 17, 2011, at 10:16 AM, David Kahn wrote:
>
> On Mon, Jan 17, 2011 at 9:48 AM, Ants Pants <antsmailinglist at gmail.com>wrote:
>
>> Hello all,
>>
>> From what I've seen, this type of question doesn't really seem to get an
>> answer on this list as most of the replies relate to failures of RSpec. If
>> this is the case, where is the best place to go to get advice about best
>> practices etc?
>>
>> I have a question about best practice. In some of my controllers only an
>> admin user can perform edit, update, show etc. So I have a before filter in
>> those controllers; ApplicationController#authorise_is_admin
>>
>> The ApplicationController#authorise_is_admin throws an AccessDenied
>> exception and that is caught in ApplicationController#access_denied
>>
>> My question is, in the spec for the calling controller, let's say
>> ProductGroups, what should I spec?
>>
>> I have a context "user is admin" and that's easy to spec, but the context
>> "user is not admin" is where I'm stuck as no actions are performed in that
>> controller but I would just like to cover that failure somehow.
>>
>> Interesting question. I had the same dilemma and decided that it took too
> much effort and test code to test this at the controller level. What I do
> (and this may or may not work for you depending on your apps security
> needs), is to have an authorize method in the User model. It returns success
> or failure based on the controller and action passed. The model looks
> something like this:
>
>   def authorize(controller_name, action_name)
>     if self.role
>       current_role = self.role.name
>     else
>       # guest user is empty user
>       current_role = 'guest'
>     end
>
>
>     case controller_name
>     when 'activations'
>       if current_role != 'guest'
>         return set_autorize_failure_value("You are already logged in to the
> system. If you are activating a new user please log out first and try
> again.")
>       end
>       return authorize_success_message
>
>     when 'feedback_supports'
>       if current_role == 'guest' || current_role == 'sysadmin'
>         return set_autorize_failure_value(LOGIN_NOTICE)
>       end
>       return authorize_success_message
> ...
>
> end
>
> Then in the spec it is real easy:
>
>   describe "user authorization - guest role" do
>     it "is authorized to access certain pages only" do
>       user = User.new
>       user.authorize('activations', 'create')[:success].should == true
>       user.authorize('home', 'index')[:success].should == false
>
>     ....
>
>     end
>   end
>
> This might not be everyone's cup of tea and I am sure I can refactor and
> make this less verbose, but what I like is having the 'dna' of all my access
> rights app wide in one place.
>
>
> Definitely agree with the idea of keeping decisions in one place. I don't
> really like the idea of 'controllers' living inside a model, but change
> 'controller_name' to 'resource_collection_name' and that solves that
> problem.
>
> I would still want to specify that the controller asks the user for
> authorization. WDYT?
>

If I am following the thread right, I should clarify that I call 'authorize'
from the application controller -- should have included this in my first
response. It is from there that the User model is invoked:

class ApplicationController < ActionController::Base

    private

    def authorize
      if current_user
        return_value = current_user.authorize(controller_name, action_name)
      else
        return_value = User.new.authorize(controller_name, action_name)
      end

      if !return_value[:success]
        flash[:notice] = return_value[:failure_message]
        if current_user
          redirect_to home_path
        else
          redirect_to login_path
        end
      end
    end

end


I would not venture to say what I have is the best but just what came up
from refactoring in search of simplifying my code and tests. I also do not
like the idea of anything dependent like a session or params or something
else from a controller getting coupled to a model, but in this case it feels
to me that the model is just a switchboard in decision-making, which for me
I would consider business logic.




>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20110121/9abe6b18/attachment.html>


More information about the rspec-users mailing list