Forum: Ruby on Rails Preferred way of dealing with url hacking & REST

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
96f5de71a8111ed44d251e869270fc03?d=identicon&s=25 blake miller (Guest)
on 2007-02-10 20:23
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
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2007-02-10 20:34
(Received via mailing list)
On 2/10/07, blake miller <rails-mailing-list@andreas-s.net> 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
821395fe70906c8290df7f18ac4ac6cf?d=identicon&s=25 Rick Olson (Guest)
on 2007-02-10 20:40
(Received via mailing list)
> 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 Olson
http://weblog.techno-weenie.net
http://mephistoblog.com
96f5de71a8111ed44d251e869270fc03?d=identicon&s=25 blake miller (Guest)
on 2007-02-10 20:45
Both of those seem like elegant solutions.  Thanks!

Rick Olson wrote:
> I usually do the opposite.
>
> class Article
>   def accessible_by?(user)
>     user && user_id == user.id
>   end
> end
> Rick Olson
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2007-02-10 20:54
(Received via mailing list)
On 2/10/07, Rick Olson <technoweenie@gmail.com> 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
96f5de71a8111ed44d251e869270fc03?d=identicon&s=25 blake miller (Guest)
on 2007-02-10 21:18
Pat Maddox wrote:
> On 2/10/07, Rick Olson <technoweenie@gmail.com> 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.
3ac33df56618745e75f62a60c50ea95a?d=identicon&s=25 Jeff (Guest)
on 2007-02-11 03:23
(Received via mailing list)
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 <rails-mailing-l...@andreas-s.net>
8217faf2bfdfa7daf10135d41ddd421e?d=identicon&s=25 Jeff Cohen (jeff)
on 2007-02-11 06:17
(Received via mailing list)
On Feb 10, 2:18 pm, blake miller <rails-mailing-l...@andreas-s.net>
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
C5a54e91a512b0b06e3d940f9c5bcb2f?d=identicon&s=25 Alan Feng (snowbug)
on 2007-02-11 10:41
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/d...

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?
96f5de71a8111ed44d251e869270fc03?d=identicon&s=25 Blake Miller (blakeage)
on 2007-02-11 15:33
Alan Feng 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/d...
>
> 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.
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2007-02-11 18:56
(Received via mailing list)
On 2/11/07, Alan Feng <rails-mailing-list@andreas-s.net> 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
This topic is locked and can not be replied to.