我有许多资源(旅行,计划等),其行动应仅限于资源所有者。
如何使用ApplicationController中定义的#require_owner方法实现代码来实现此目的?理想情况下,代码将查找所有者的继承链,因此before_filter将处理:belongs_to:travel that belongs_to:user的注释。
class TripsController < ApplicationController
belongs_to :member
before_filter :require_owner
...
end
答案 0 :(得分:5)
我没有完全按照描述(评论真的归旅行老板所有吗?),但是jonnii的回答略有扩展,这是一个限制行程控制器的例子:
class ApplicationController < ActionController::Base
...
protected
# relies on the presence of an instance variable named after the controller
def require_owner
object = instance_variable_get("@#{self.controller_name.singularize}")
unless current_user && object.is_owned_by?(current_user)
resond_to do |format|
format.html { render :text => "Not Allowed", :status => :forbidden }
end
end
end
end
class TripsController < ApplicationController
before_filter :login_required # using restful_authentication, for example
# only require these filters for actions that act on single resources
before_filter :get_trip, :only => [:show, :edit, :update, :destroy]
before_filter :require_owner, :only => [:show, :edit, :update, :destroy]
...
protected
def get_trip
@trip = Trip.find(params[:id])
end
end
假设模型如下:
class Trip < ActiveRecord::Base
belongs_to :owner, :class_name => 'User'
...
def is_owned_by?(agent)
self.owner == agent
# or, if you can safely assume the agent is always a User, you can
# avoid the additional user query:
# self.owner_id == agent.id
end
end
login_required
方法(由restful_authentication或authlogic提供或依赖auth插件)确保用户已登录并向用户提供current_user
方法,get_trip
设置trip实例变量,然后在require_owner
中检查。
如果模型已实现is_owned_by?
方法,则此模式可以适用于任何其他资源。如果您在资源是评论时尝试检查它,那么您将进入CommentsController
:
class CommentsController < ApplicationController
before_filter :login_required # using restful_authentication, for example
before_filter :get_comment, :only => [:show, :edit, :update, :destroy]
before_filter :require_owner, :only => [:show, :edit, :update, :destroy]
...
protected
def get_comment
@comment = Comment.find(params[:id])
end
end
使用Comment
模型,如下所示:
class Comment < ActiveRecord::Base
belongs_to :trip
# either
# delegate :is_owned_by?, :to => :trip
# or the long way:
def is_owned_by?(agent)
self.trip.is_owned_by?(agent)
end
end
确保在执行此操作时检查日志,因为如果您不小心,依赖关联的检查可能会导致大量查询。
答案 1 :(得分:2)
有几种不同的方法可以做到这一点。你一定要看看acl9插件(http://wiki.github.com/be9/acl9/tutorial-securing-a-controller)。
如果您决定自己想要这样做,我建议您这样做:
class Trip < ...
def owned_by?(user)
self.user == user
end
end
class Comment < ...
delegate :owned_by?, :to => :trip
end
# in your comment controller, for example
before_filter :find_comment
before_filter :require_owner
def require_owner
redirect_unless_owner_of(@commemt)
end
# in your application controller
def redirect_unless_owner_of(model)
redirect_to root_url unless model.owned_by?(current_user)
end
请原谅我,如果有任何语法错误=)我希望这有帮助!
答案 2 :(得分:0)
Acl9是一个授权插件。我会给你链接,但我没有剪切和粘贴我的iPhone。如果我到达计算机时没有其他人提供链接,我会帮你的。或者你可以google。任何。 :)
我刚刚开始使用它,但它有一个非常简单的界面。您只需创建一个角色表和roles_user
。如果您决定使用它,请告诉我它是怎么回事。
答案 3 :(得分:0)
或者只使用继承的资源:
InheritedResources还引入了另一个名为begin_of_association_chain的方法。当你想要根据@current_user创建资源并且你有像“account / projects”这样的网址时,它主要用于。在这种情况下,你必须在你的行动中做@ current_user.projects.find或@ current_user.projects.build。
您只需执行以下操作即可处理:
class ProjectsController < InheritedResources::Base
protected
def begin_of_association_chain
@current_user
end
end