views:

59

answers:

4

At the moment, any logged in user can go to http://localhost:3000/notes/note_id and view the note there. How do I restrict this so that you can only see notes that belong to you? Thanks for reading.

+2  A: 

In the NotesController #show action, redirect or show a permission denied error if the user_id on the note doesn't == the logged in user id.

Another solution is to put this code in a before_filter in the NotesController, since the same validation is performed for the #edit and #delete methods.

Edit: Putting all the suggestions together (Sorry if this has been confusing):

Edit2: Using Veeti's association answer, which I always seem to forget, we can add current_user.notes.find() to the mix. Like he said, your current_user needs to return a User object, and you'll need a has_many :notes in your User model.

class NotesController < ApplicationController
  before_filter :check_ownership, :except => [:new, :create, :index]

  #.. new, create, index, show, edit, delete actions

  private

  def check_ownership
    redirect_to :back unless current_user.notes.find(params[:id])
  end
end
Jon Smock
@Jon - Thanks for your answer. So I should put the redirect code in every action in the NotesController I imagine?
ben
You could also use a `before_filter` method to execute that action before every action: `before_filter :check_ownership, :except => [:new, :create, :index]`
unsorted
@ben No, it's probably best to put it in the before_filter, because you'll have the same code duplicated for some of the other actions (edit, delete). I'll edit my answer; I just wanted to answer your specific question.
Jon Smock
@Jon Not confusing at all, I should have included that question in the original question. Thanks so much for your help
ben
A: 

I like using acl9 as an authentication which has a the concept of an object owner. Then you can put in a line like

access_control do
  allow :owner, :of => :note, :to => [:show, :edit, :update]
end

See http://wiki.github.com/be9/acl9/tutorial-securing-a-controller (in particular, step 4) for more details.

If you don't want to use a plugin, Jon's solution makes sense.

unsorted
I'm not sure why we were downvoted. Here's a +1, because I think your answer was helpful and valid.
Jon Smock
A: 

The best way to achieve this is using before_filter. You can read about the details, but essentially, it runs a method before the action is called. In this method, you can check to see if the person attempting access to the note actually has permission to do so. Another good thing about this approach is that you can put the method in ApplicationController, lib/, etc, and add the before_filter to whatever controllers or actions need it. Here's a simple example:

application_controller.rb:

class ApplicationController < ActionController:Base

def verify_note_permission
  current_user.id == Note.find(params[:id]).user_id or redirect_to :back
end

notes_controller.rb

class NotesController < ApplicationController
  before_filter :verify_note_permission
  ...
end

This will check to ensure the current user's id matches the ID on the document, or it redirects back to wherever they came from. You could also add flash messages here along with a custom check for permissions implemented in the model. (Probably belongs in the model anyways).

Preston Marshall
I don't think you should be putting the verify_note_permission method in the ApplicationController. If anything, you should make it protected and pass the note_id as a parameter instead of pulling it directly from params.
Jon Smock
+2  A: 

Assuming that you have a method called current_user which returns the current User, you could use the Note relationship on the User to only search for a note of theirs with the specified ID, so instead of:

@note = Note.find(params[:id])

do

@note = current_user.notes.find(params[:id])

(Of course, you will need to specify associations in your models.)

Veeti
+1 This is helpful.
Jon Smock
You'll have to duplicate the code for each controller action. Using the before_filter avoids code duplication. Using the except will make sure that each new action is protected by default.
David
Nothing prevents you from using a `before_Filter` with this method - in fact, I never said that you shouldn't use one.
Veeti