阻止其他已登录用户访问“编辑”页面

我正在构建一个小型Web应用程序,允许用户列出他们的目标。 我希望用户只能编辑自己的内容。 我已经有一个身份validation函数作为before_filter,它会检查以确保某人已登录,但它不会检查用户是否是该内容的创建者。 我尝试创建第二个名为correct_user的before_filter,其代码如下:

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

此外,这是运行get请求以编辑我自己的内容的服务器输出

 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 

为清楚起见,我使用的user_id是101,而我正在尝试编辑的goal_id是31.有人可以解释到底发生了什么吗?

另外,我知道你可以通过使用名为CanCan的gem来解决这个问题(因为类似的问题得到了解答),但有没有办法在不使用gem的情况下做到这一点? 看起来我的简单小function应该可以工作,但有人可以解释为什么它不行吗?

params是所有参数(通过url或表单字段等)发送到您的操作的哈希值。 参数的名称(如果存在于URL中)在路径文件中定义。 对于你的目标控制器路线,你可能(大概)有:

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

因为你得到/goals/31/edit ,所以params[:id]是31,你正在编辑的目标的id。 correct_user的第一行是查找id与params hash(goal_id)中的id匹配的User。 所以,你应该这样做:

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

这说,找到有人想要编辑的目标(来自params [:id]),并给我与之关联的用户(你没有发布你的目标模型,我假设目标为belongs_to:用户但你可能已命名它改为“创造者”或“所有者”。 如果用户与登录的当前用户不同,则重定向。您之前的代码试图找到与正在编辑的目标具有相同ID的用户。

鉴于以下假设:

  1. 用户模型: has_many :goals
  2. 目标模型: belongs_to :user
  3. 路线编辑目标: /goals/:id/edit
  4. 目标控制器,编辑操作已通过身份validation(因此您肯定会有current_user

您应该能够像这样访问目标:

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

这将查找范围@goal为属于current_user目标,因此@goal将始终属于正确的用户。

params hash中的参数id指的是目标id,而不是用户id。 因此,为什么你看到一个问题。

可能你想做的事情是这样的

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

其他人回答了你的主要问题,但我想这样说:我强烈建议使用CanCan,即使对于一个非常小的项目。 它非常易于使用,它将帮助您,并且您将拥有令人敬畏的干净代码

例如,在您的情况下,您可以将此行放在ability.rb以管理更新用户的目标

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

并在您的控制器中只需在顶部执行load_and_authorize_resource 。 没有手动before_filters,没有检查任何条件或类似的东西。

无论你需要在link_to_if(can?(:update, goal) , "edit goal", goal_path(goal) ){}什么,比如说在索引视图中,在列出链接时你只需要输入link_to_if(can?(:update, goal) , "edit goal", goal_path(goal) ){}