Abstracting ownership verification out of Controller


#1

Right now I have a controller for “events” that belong to a specific
user. I only want the creator to be able to edit or delete the event.

I’ve got the proper foreign keys set up.

I’ve finally arrived at the point where I can take baby steps with
code, but looks like my first steps are in flagrant violation of the
DRY principle.

Here’s what I have so far in the “EventsController” and I know it’s
ugly (but it works).

def update
@event = Event.find(params[:id])
if @event.user_id == session[:user] &&
@event.update_attributes(params[:event])
flash[:notice] = ‘Event was successfully updated.’
redirect_to :action => ‘show’, :id => @event
else
flash[:notice] = ‘You do not have permission to edit.’
redirect_to :action => ‘list’
end
end

def destroy
@event = Event.find(params[:id])
if @event.user_id == session[:user]
@event.destroy
redirect_to :action => ‘list’
flash[:notice] = ‘Event was deleted.’
else
flash[:notice] = ‘You do not own this event.’
redirect_to :action => ‘list’
end
end

What I would like to do is extract the “if @event.user_id ==
session[:user]” kind of verification from controllers since I can
imagine calling this a lot as I add more models with a variety of
permissions?

Is there a better strategy to approach this?

Sam


#2

On Tue, 21 Feb 2006 22:06:06 +0900, SB wrote:

Right now I have a controller for “events” that belong to a specific
user. I only want the creator to be able to edit or delete the event.

Seems like Bill K.'s brand-new authorization DSL will help you, once
somebody writes an implementation including permit_set:

http://www.billkatz.com/authorization

Jay L.


#3

Sam-

Are you storing the whole user object in the session or just the

user.id? If you have the whole user object in thereyou can do it like
this instead to limit the fin and update to the user who is owner:

@event = session[:user].events.find(params[:id])

What that will do is add this to your where clause in :conditions :

AND user_id = whatever the session[:user].id is

If you dont have the user object in the session and just the id then
you can have a method set up that sets the current_user up:

def current_user
User.find(session[:user])
end

And then you would do your Event finder like this:

@event = current_user.events.find(params[:id])

Hope that helps

-Ezra

On Feb 21, 2006, at 5:06 AM, SB wrote:

ugly (but it works).
flash[:notice] = ‘You do not have permission to edit.’
else

Is there a better strategy to approach this?

Sam


Rails mailing list
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails

-Ezra Z.
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
removed_email_address@domain.invalid


#4

Thank you all for the helpful suggestions, it definitely set me in the
right direction.
Yes, I did read all the resources suggested and it certainly gives me
an indication of what’s ahead.

I ended up using “before_filter” to accomplish this. Right now it’s
right in the controller but if it crops up in other controllers, I
might try to get it into “application.rb”.

Since I’m building up from scratch, I’d rather keep dependency on
libraries and plugins to a minimum since I need to learn rails at the
same time rather than rush something out the door or read third party
code that’s beyond me.

One thing that throws me off with plugins, is that any given plugin
might represent a couple styles of coding. This can be confusing for
a beginner.

Here’s how I rewrote my code:

before_filter :verify_permission, :only => [:edit, :update, :destroy]

def update
if @event.update_attributes(params[:event])
flash[:notice] = ‘Event was successfully updated.’
redirect_to :action => ‘show’, :id => @event
else
redirect_to :action => ‘list’
end
end

def destroy
@event.destroy
redirect_to :action => ‘list’
flash[:notice] = ‘Event was deleted.’
end

private
def verify_permission
@event = Event.find(params[:id])
if @event.user_id == session[:user]
return true
else
flash[:notice] = ‘You do not have permission for this event.’
redirect_to :action => ‘list’
end
end

Basically, I restored “update” and “destroy” to what it was before
only taking out “@event = Event.find(params[:id])” since it was now
part of “verify_permissions”.

It gives me a warm feeling to post something on this list before bed
and wake up to see responses. Now I know how the shoemaker felt when
the elves came to the rescue.

And now for another session of solitary Subversion tag…

Sam


#5

Hi !

2006/2/21, Ezra Z. removed_email_address@domain.invalid:

    Are you storing the whole user object in the session or just the

user.id? If you have the whole user object in thereyou can do it like
this instead to limit the fin and update to the user who is owner:

This article on my blog might be interesting:
http://blog.teksol.info/articles/2005/10/21/model-serialization-in-session

Bye !


#6

On 2/21/06, Jay L. removed_email_address@domain.invalid wrote:

On Tue, 21 Feb 2006 22:06:06 +0900, SB wrote:

Right now I have a controller for “events” that belong to a specific
user. I only want the creator to be able to edit or delete the event.

Seems like Bill K.'s brand-new authorization DSL will help you, once
somebody writes an implementation including permit_set:

Actually, the current plugin lets you handle Sam’s case pretty easily,
even
without permit_set. The permission check would be handled by a
user_has_role? method in the Event model class. We hardwire a
‘moderator’
role into the Event model.

class Event < ActiveRecord::Base
def user_has_role?( user, role )
return true if role == ‘moderator’ and self.user_id == user.id
false
end
end

Then his controller looks like this:

class EventController < ApplicationController
permit “moderator of :event”, :only => [:edit, :update, :destroy]

def edit

end

end

This works because the “event” in the permission expression is checked
against @event, any :event hash, and finally, if params[:id] is not nil,
it
uses Event.find(params[:id]). This is an added convention that
facilitates
standard use. I’ve just started working with Ezra on refining the
authorization DSL, and we may decide to make things more explicit. But
right
now, the plugin at http://www.billkatz.com/authorization will support
authorizations like the above example.
-Bill