Prevent other users who are logged in from the edit page

I am creating a small web application that allows users to list their goals. I want users to be able to edit their content. I already have an authentication function like before_filter that checks that someone is signed, but it does not check if the user is the creator of the content. I tried to create a second before_filter named correct_user, which has the following code:

def correct_user @user = User.find(params[:id]) redirect_to(user_path(current_user)) unless current_user?(@user) end 

In addition, a server is issued here on which a get request is executed to edit my own content.

 Started GET "/goals/31/edit" for 127.0.0.1 at 2011-05-18 15:22:38 -0400 Processing by GoalsController#edit as HTML Parameters: {"id"=>"31"} User Load (0.2ms) SELECT "users".* FROM "users" WHERE ("users"."id" = 101) LIMIT 1 User Load (0.2ms) SELECT "users".* FROM "users" WHERE ("users"."id" = 31) LIMIT 1 Redirected to http://localhost:3000/users/101 Completed 302 Found in 49ms Completed 302 Found in 49ms 

For clarity, the user_id I am using is 101, and the id_ target I'm trying to change is 31. Can someone explain what is happening?

In addition, I know that you can navigate this problem using a gem called CanCan (as they answered the same question), but is there a way to do this without using a gem? It seems my simple little function should work, but can someone explain why this is not so?

+4
source share
4 answers

params is a hash of all passed parameters (via url or form fields, etc.) for your action. The parameter name, if present in the URL, is defined in the routes file. For your purposes, driving routes, you probably (presumably):

 goals_path: /goals/ goal_path: /goals/:id edit_goal_path: /goals/:id/edit 

Since you get /goals/31/edit , params[:id] is 31, the identifier of the goal you are editing. The first line in correct_user is the search for a user whose identifier matches the identifier in the params hash (goal_id). So you should do something like this:

 def correct_user user = Goal.find(params[:id]).user if params[:id] redirect_to user_path(current_user) unless current_user?(user) end 

This says, find the goal someone wants to edit (from params [: id]) and give me the user associated with it (you have not published your target model, I assume that the target belongs to: user, but you may have named its "creator" or "owner"). Forwarding if the user does not match the current user. Your previous code tried to find a user with the same identifier as the target being edited.

+2
source

Given the following assumptions:

  • User Model: has_many :goals
  • Target Model: belongs_to :user
  • The route for editing the goal: /goals/:id/edit
  • Circuit controller, the edit action is authenticated (so you will definitely have current_user )

You must have access to such a goal:

 def edit @goal = current_user.goals.find(params[:id]) rescue redirect_to(user_path current_user) end 

This will cover targets owned by current_user , so @goal will always belong to the correct user.

+2
source

The parameter identifier in the params hash refers to the identifier of the target, and not to the user identifier. Therefore, why do you see the problem.

Probably what you want to do is something like

 def correct_user @goal = Goal.find(params[:id]) redirect_to(user_path(current_user)) unless current_user?(@goal.user) end 
+1
source

Others answered your main problem, but I want to say the following: I highly recommend using CanCan even for a very small project. It is very easy to use, and it will help you a lot, and you will have great clean code.

for example, in your situation, you can put this line in ability.rb to control the updating of user goals.

can :update, Goal, :user_id => user.id

and in your controller just click load_and_authorize_resource at the top. No manually before_filters, do not check any conditions or anything like that.

and wherever you need to change something to edit the goal, for example, in the index view, when listing links, you just put something like link_to_if(can?(:update, goal) , "edit goal", goal_path(goal) ){}

0
source

All Articles