Search code examples
ruby-on-railsbefore-filter

rails before_filter preventing access to controllers


I've got an app where the user can nominate a keyholder who can also view their account. I've got a before_filter than means that only the account holder, or their keyholder, can view their account. This code works fine for either person viewing the user's home page, but I can't do anything further - I am currently logged in as the keyholder, and I can't log out, or add 'notes' to either account (right now the keyholder has unrestricted access to their own account and the person they are keyholder for). Please can anyone help?

The before_filter is:

def correct_user
        @user = User.find(params[:id])

        unless (@user && current_user.id == @user.id) || ((current_user.access_id==@user.id)&&(current_user.id==@user.access_id))
          redirect_to root_path
        end
      end

and the error I am getting when trying to e.g. create a note is:

ActiveRecord::RecordNotFound in NotesController#new 
Couldn't find User without an ID

it is referring to the @user line in the before_filter.

How come when I am logged in as the keyholder, I can view the homepage, but do nothing else? Thanks!

UPDATE:

Updated before_filter (in application_controller.rb):

def correct_user
        if params[:id]
          @user = User.find(params[:id])

          unless (@user && current_user.id == @user.id) || ((current_user.access_id==@user.id)&&(current_user.id==@user.access_id))
            redirect_to root_path
          end
        else
          redirect_to root_path
        end
      end

Console output on note creation:

Started POST "/notes" for 127.0.0.1 at 2013-02-28 14:10:49 +0000
Processing by NotesController#create as HTML
  Parameters: {"utf8"=>"V", "authenticity_token"=>"qMDHQAoC4l3Be5YZKSH1AJ9E5zS1D
kMNCW2KzUZ38gM=", "note"=>{"user_id"=>"16", "content"=>""}, "commit"=>"Update Note"}
Redirected to http://localhost:3000/
Filter chain halted as :correct_user rendered or redirected
Completed 302 Found in 98ms (ActiveRecord: 0.0ms)


Started GET "/" for 127.0.0.1 at 2013-02-28 14:10:49 +0000
Processing by PublicController#index as HTML
  ←[1m←[36mUser Load (3.0ms)←[0m  ←[1mSELECT "users".* FROM "users" WHERE "users
"."id" = 16 LIMIT 1←[0m
  Rendered public/index.html.erb within layouts/application (5.0ms)
  ←[1m←[36mTimeline Load (3.0ms)←[0m  ←[1mSELECT "timelines".* FROM "timelines"
WHERE "timelines"."user_id" = 16 LIMIT 1←[0m
  ←[1m←[36mMessageBoard Load (2.0ms)←[0m  ←[1mSELECT "message_boards".* FROM "me
ssage_boards" WHERE "message_boards"."user_id" = 16 LIMIT 1←[0m
  Rendered partials/_menuoptions.html.erb (53.0ms)
Completed 200 OK in 551ms (Views: 535.0ms | ActiveRecord: 16.0ms)

Solution

  • Try:

    def correct_user
                if current_user
                  @user = User.find(current_user.id)
    
                  unless (@user && current_user.id == @user.id) || ((current_user.access_id==@user.id)&&(current_user.id==@user.access_id))
                    redirect_to root_path
                  end
                else
                  redirect_to root_path
                end
              end
    

    Actually, there is no params[:id] like thing here. The current_user is the user whom you are checking so you can directly find with current_user.id as above. Replace the code with above and rectify for possible best if you find other. It is just an idea for implementation.