Preferred way of dealing with url hacking & REST


#1

I’m just getting started with REST-ful development, which typically
embeds the id of objects in the url, like /articles/8. This, as anyone
knows, can easily be changed to articles/10 by anybody, and I was
wondering what is the preferred way of dealing with this in REST-ful
development.

My solution, or the one that seems obvious, is to compare the id with
the user’s session[:user_id] to make sure they have access to this
resource, and to throw an error otherwise. But that requires an extra
query on every page request for verification. Was just wondering if
anyone else had a clever solution, or if there was a preferred way of
doing this.

Thanks,
Blake


#2

On 2/10/07, blake miller removed_email_address@domain.invalid wrote:

query on every page request for verification. Was just wondering if
anyone else had a clever solution, or if there was a preferred way of
doing this.

I usually do write a simple access? method on my User model. For
example:

class User
def access?(article)
id == article.user_id
end
end

Then in your controller you do use a before_filter

class ArticlesController < ApplicationController
before_filter :check_article_access

def show
end

protected
def check_article_access
@article = Article.find params[:id]
unless current_user.access? @article
redirect_to user_url(current_user)
return false
end
end
end

There’s still only one query, you just create the @article instance
variable in a different method.

hth

Pat


#3

I usually do write a simple access? method on my User model. For example:

class User
def access?(article)
id == article.user_id
end
end

I usually do the opposite.

class Article
def accessible_by?(user)
user && user_id == user.id
end
end


Rick O.
http://weblog.techno-weenie.net
http://mephistoblog.com


#4

Both of those seem like elegant solutions. Thanks!

Rick O. wrote:

I usually do the opposite.

class Article
def accessible_by?(user)
user && user_id == user.id
end
end
Rick O.


#5

Pat M. wrote:

On 2/10/07, Rick O. removed_email_address@domain.invalid wrote:

class Article
def accessible_by?(user)
user && user_id == user.id
end
end

Is that a better way, or is it just preference?

I throw the method on user because it lets me build out a permission
system as needed. I start with checking ids, and then maybe it
becomes

def access?(article)
role == “root” || article.user_id == id
end

and then eventually we might end up using a full-fledged permission
system.

Pat
The thing that stuck out about putting the code in the user model is
that for every type of object accessed, like (article, product,
magazine), you’d add a function to the user model, which would make your
User model ugly. If you put this code in the model object, you end up
with just one or two functions on each object.

Then again, because Ruby is so sweet, you could put one access? function
in User, allowing a dynamic parameter (article, magazine, product),
check the type of the passed in parameter, and have a big switch
statement to verify access.

I guess it’s really a matter of preference, and down the road you’d
probably have a ResourceAccess controller or something anyway.


#6

If user has many articles and article belongs to user, ActiveRecord
affords you the option of referencing articles within the user’s scope
like this:

@article = @user.articles.find(article_id)
or:
@article = @user.articles.create(:params[:article])

On Feb 10, 3:18 pm, blake miller removed_email_address@domain.invalid


#7

On 2/10/07, Rick O. removed_email_address@domain.invalid wrote:

class Article
def accessible_by?(user)
user && user_id == user.id
end
end

Is that a better way, or is it just preference?

I throw the method on user because it lets me build out a permission
system as needed. I start with checking ids, and then maybe it
becomes

def access?(article)
role == “root” || article.user_id == id
end

and then eventually we might end up using a full-fledged permission
system.

Pat


#8

On Feb 10, 2:18 pm, blake miller removed_email_address@domain.invalid
wrote:

def access?(article)
role == “root” || article.user_id == id
end
The thing that stuck out about putting the code in the user model is
that for every type of object accessed, like (article, product,
magazine), you’d add a function to the user model, which would make your
User model ugly. If you put this code in the model object, you end up
with just one or two functions on each object.

Actually, no. As long as all of those objects respond to the user_id
message, you’re golden - perhaps if I rename the argument that Pat
used it will be clearer:

def access?(model)
id == model.user_id
end

So for every model the belongs_to :user, you can ask the user object
if it can access this model. If you want to be extra safe:

def access?(model)
false unless model.responds_to? ‘user_id’
id == model.user_id
end

This is where Ruby really shines above the statically-typed languages
I used to use a long time ago in a galaxy far, far way.

Jeff
softiesonrails.com


#9

I am new to RoR and RESTful. I just listened to the David’s keynote at
RailsConf and I think the what suggested above are not the RESTful way.

You can find the keynote video and slides at:
http://blog.scribestudio.com/articles/2006/07/09/david-heinemeier-hansson-railsconf-2006-keynote-address

According to David, the RESTful way of modeling what you have there is
to introduce a new active model called (for example) Writings, which
represents the relationship of a user’s articles. Then creating a
Writing object is adding an article to the user and you can easily check
the permission by trying to find the Writing object by both user_id and
article_id.

Any thoughts?


#10

On 2/11/07, Alan F. removed_email_address@domain.invalid wrote:

I am new to RoR and RESTful. I just listened to the David’s keynote at
RailsConf and I think the what suggested above are not the RESTful way.

What’s not RESTful about it?

According to David, the RESTful way of modeling what you have there is
to introduce a new active model called (for example) Writings, which
represents the relationship of a user’s articles. Then creating a
Writing object is adding an article to the user and you can easily check
the permission by trying to find the Writing object by both user_id and
article_id.

Any thoughts?

User#articles already represents the relationship between a user and
his articles. Throwing something in between is just some weird
overhead.

You can of course really easily handle permissions by calling
current_user.articles.find(params[:id]). That does the scoping for
you and everything.

The “missing model” usually occurs with a many to many relationship.

Pat


#11

Alan F. wrote:

I am new to RoR and RESTful. I just listened to the David’s keynote at
RailsConf and I think the what suggested above are not the RESTful way.

You can find the keynote video and slides at:
http://blog.scribestudio.com/articles/2006/07/09/david-heinemeier-hansson-railsconf-2006-keynote-address

According to David, the RESTful way of modeling what you have there is
to introduce a new active model called (for example) Writings, which
represents the relationship of a user’s articles. Then creating a
Writing object is adding an article to the user and you can easily check
the permission by trying to find the Writing object by both user_id and
article_id.

Any thoughts?
Yea, in my setup I have:
User
Account
UserAccount

I could do UserAccount.exists?( user, account ), but it feels right to
say “Does user have access to this account”, than to say, “Does user and
account relationship exist”. I think it’s just a matter of what sounds
intuitive, but I may not be thinking RESTfully enough.