2011-05-18 95 views
4

我正在构建一个允许用户列出目标的小型Web应用程序。我希望用户只能编辑自己的内容。我已经获得了authenticate函数作为before_filter进行检查以确保有人登录,但它不检查用户是否为内容的创建者。我试图创建一个第二的before_filter称为correct_user具有代码如下:防止其他登录用户访问'编辑'页面

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的情况下做到这一点?这似乎是我的简单小功能应该工作,但有人可以解释为什么它不?

回答

2

params是将所有参数(通过url或表单域等)发送到您的操作的散列。参数的名称(如果存在于URL中)在路由文件中定义。对于你的目标控制器的路线,你可能(可能)有:

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

因为你得到/goals/31/editparams[:id]是31,你正在编辑的目标的ID。 correct_user中的第一行是找到其id与param散列(goal_id)中的id相匹配的用户。所以真的,你应该做这样的事情:

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

这是说,发现有人想编辑的目标(从PARAMS [:编号]),并给了我与它相关联的用户(你没” t发布您的目标模型,我假设Goal belongs_to:user,但您可能已将其命名为“creator”或“owner”)。如果用户与当前登录的用户不相同,则重定向。以前的代码尝试查找与编辑的目标ID相同的用户。

+0

说,在索引视图,这清除了很多东西,谢谢!但为什么你在第一行的末尾添加“if params [:id]”?离开它的后果是什么? – 2011-05-18 22:56:49

+0

取决于你如何定义你的before_filter。如果before过滤器在每个动作上运行,它将在收集动作(index,new)上引发RecordNotFound异常。如果你之前的过滤器只在编辑,更新,销毁,创建之前运行,那么可能没有必要。基本上,如果第一行在params散列中找不到id,而不是执行并抛出异常,则不执行第一行。 – 2011-05-18 23:11:25

+0

是的,我只有在某些行动上运行它。再次感谢! – 2011-05-18 23:20:56

1

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 
+0

'@goal = User.find'?可能有一个错字! :) – 2011-05-18 21:28:38

+0

@Brett,哈哈,谢谢。 – Vadim 2011-05-18 21:29:07

2

考虑以下假设:

  1. 用户模式:has_many :goals
  2. 目标模式:belongs_to :user
  3. 路线编辑目标: /goals/:id/edit
  4. 目标控制器,编辑acti在通过身份验证(所以你一定有一个current_user

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

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

这将范围寻找到属于current_user目标,使@goal将始终属于正确的用户。

0

其他回答你的主要问题,但我想说的是:我强烈建议使用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)){}