Rails 3, help controlling access to a record based on the user id

Hello, I'm a Rails newbie.... Here's what I'm trying to do....

I created a scaffold for notes (t.text :content, t.integer :user_id) What I want to do now is only allow user's to view notes that they created. ie (== user_id)

In my /app/controllers/notes_controller.rb

I have the following:

    class NotesController < ApplicationController       before_filter :authenticate       before_filter :correct_user     .     .     .     def correct_user       @noteuserid = Note.find(:conditions=>["note.user_id=?", @noteuserid])       redirect_to(root_path) unless current_user?(@noteuserid)     end

I'm having problems understanding how to write the following line: @noteuserid = Note.find(:conditions=>["note.user_id=?", @noteuserid])

Right now I'm using the system in the Rails 3 Tutorial Book: railstutorial.org/chapters/sign-in-sign-out#sec:current_user

Seems like the problem is current_user is an object, not an ID... Not sure how to make the two comparable?

Thanks

This hack ends up working. Is there a cleaner, ruby trick to getting this to work?

      @note = Note.find(params[:id])       @note_userid = @note.user_id       @current_userid = current_user.id       redirect_to(root_path) unless @current_userid == @note_userid

thxs!

The cleanest method is to scope your notes by user instead of searching the whole class:

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

Ed thanks for the reply. I'd love to hear more... I tried your suggestion but it error'd:

"undefined method `Notes' for nil:NilClass"

Two possible issues:

1. Do you have the relationship declared in the models?

class Note < ActiveRecord   belongs_to :user end

class User < ActiveRecord   has_many :notes end

2. If @user is a nil object, it will throw an error. Set @user to the current_user in your before_filter. If there is a possibility of hitting that point with a nil user, then change the line to read something like this:

@note = @user ? @user.notes.find(params[:id]) : nil

which is a shorter way of saying

if @user.nil?   @note = nil else   @note = @user.notes.find(params[:id]) end

Thanks for the reply, I do have the relationships declared above in the models... I've been learning and following the rails 3 book here: http://railstutorial.org/chapters/a-demo-app#sec:microposts_resource

I tried your suggestion "@note = @user ? @user.notes.find(params[:id]) : nil " and while it didn't error which was good, it didn't work, it ended up redirecting... Full code:

class NotesController < ApplicationController   before_filter :correct_user, :only => :show . . .   def show     @note = Note.find(params[:id])

    respond_to do |format|       format.html # show.html.erb       format.xml { render :xml => @note }     end   end

  private     def correct_user       #@note = Note.find(params[:id])       #@note_userid = @note.user_id       @note = @user ? @user.notes.find(params[:id]) : nil       @current_userid = current_user.id       redirect_to(root_path) unless @current_userid == @note_userid     end   end

please check the post "Use scope access" on rails-bestpractices.com, http://rails-bestpractices.com/posts/3-use-scope-access, it tells you how to use the Ed's way to strict access and rescue the exceptions.

You don't seem to be setting @note_userid anywhere. The check is redundant though - doing @user.notes.find(...) ensures that the returned note (or notes) have a user_id that is @user.id. You obviously need to set @user to somethign first (or if current_user is set appropriately by your authentication stuff then you could do current_user.notes.find(...).

Fred

Thanks all, this ended up working which I believe scopes correctly... Thoughts?

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