Ruby on rails 让通用的Pre_过滤器不那么难看?
我有一些Prefore过滤器,用于按资源级别控制对资源的访问。基本思路如下:Ruby on rails 让通用的Pre_过滤器不那么难看?,ruby-on-rails,ruby,Ruby On Rails,Ruby,我有一些Prefore过滤器,用于按资源级别控制对资源的访问。基本思路如下: 用户可以是用户或管理员,并且可以基于“访问”表访问特定资源 对管理员、所有者、特定用户或所有人的访问可以限制资源/方法 一些代码示例最好地说明了这一点。我们有4种应用程序级方法,它们通过before\u filter添加到调用链中。下面是示例控制器类的顶部: before_filter :require_user before_filter :get_object, :only=>[:show, :edit, :
用户
或管理员
,并且可以基于“访问”表访问特定资源管理员
、所有者
、特定用户或所有人的访问可以限制资源/方法before\u filter
添加到调用链中。下面是示例控制器类的顶部:
before_filter :require_user
before_filter :get_object, :only=>[:show, :edit, :update, :destroy]
before_filter :require_access, :only=>[:show]
before_filter :require_owner, :only=>[:edit, :update, :destroy]
如您所见,首先我们要求用户登录以访问此控制器中的任何方法。下面是3个方法(在application.rb中定义),以便您可以看到它们的外观:
private
def get_object
begin
class_name = controller_name.gsub("Controller","").downcase.singularize
instance_variable_set "@#{class_name}".to_sym, class_name.capitalize.constantize.find(params[:id])
rescue
flash[:error] = "You do not have access to that #{class_name}."
redirect_to "/" and return
end
end
private
def require_owner
class_name = controller_name.gsub("Controller","").downcase.singularize
accessable = instance_variable_get("@#{class_name.downcase}")
unless accessable.user == current_user
flash[:error] = "You do not have access to that #{class_name.downcase}."
redirect_to "/" and return
end
end
private
def require_access
class_name = controller_name.gsub("Controller","").downcase.singularize
accessable = self.instance_variable_get("@#{class_name.downcase}")
unless current_user.has_access?(accessable)
flash[:error] = "You do not have access to that #{class_name.downcase}."
redirect_to "/" and return
end
end
就我所知,从编码的角度来看,这一切都很好。但它真他妈的丑!特别是以下几行:
class_name = controller_name.gsub("Controller","").downcase.singularize
obj = instance_variable_get("@#{class_name.downcase}")
或
有人知道我在这里做什么更优雅一点吗?好吧,你可以做以下两件事: 1-首先删除另外两条
private
语句,第一条就足够了。请记住,private
、protected
和public
只是Ruby类中定义的其他方法
2-最好重构代码以在其方法中设置对象创建:
def create_object
class_name = controller_name.gsub("Controller","").downcase.singularize
obj = instance_variable_get("@#{class_name.downcase}")
end
def locate_object
instance_variable_set "@#{class_name}".to_sym class_name.capitalize.constantize.find(params[:id])
end
你可以做以下两件事: 1-首先删除另外两条
private
语句,第一条就足够了。请记住,private
、protected
和public
只是Ruby类中定义的其他方法
2-最好重构代码以在其方法中设置对象创建:
def create_object
class_name = controller_name.gsub("Controller","").downcase.singularize
obj = instance_variable_get("@#{class_name.downcase}")
end
def locate_object
instance_variable_set "@#{class_name}".to_sym class_name.capitalize.constantize.find(params[:id])
end
我不知道是否有真正干净的方法可以做到这一点,但这里有一些建议:
首先,创建一个控制器ResourceController
,并让所有相关控制器从中继承。(如果此授权适用于所有控制器,则只需使用ApplicationController
)
现在,在名为model\u name
的超类中实现一个私有方法(就像您的class\u name
),这样您就不必在每次需要时都派生它。而且,您应该能够通过简单地执行以下操作来推导:
def model_name
controller_name.classify
end
您还可以在返回实际类的超类中实现model
方法:
def model
model_name.constantize
end
此时,您还可以添加如下内容:
def current_object
model.find(params[:id])
end
def current_object_var_name
"@#{model_name.underscore}"
end
除了总是使用@object
或类似的东西之外,我看不到使用实例变量\u get/set
的快捷方法。但如果您不想这样做,那么这些行现在就简单一点:
instance_variable_set current_object_var_name, current_object
obj = instance_variable_get(current_object_var_name)
在这一点上,您的代码应该更具可读性,并且更加美观
您可能还想了解一些最新的Rails授权插件正在做什么,尤其是和。我不知道是否有一种真正干净的方法可以做到这一点,但这里有一些建议:
首先,创建一个控制器ResourceController
,并让所有相关控制器从中继承。(如果此授权适用于所有控制器,则只需使用ApplicationController
)
现在,在名为model\u name
的超类中实现一个私有方法(就像您的class\u name
),这样您就不必在每次需要时都派生它。而且,您应该能够通过简单地执行以下操作来推导:
def model_name
controller_name.classify
end
您还可以在返回实际类的超类中实现model
方法:
def model
model_name.constantize
end
此时,您还可以添加如下内容:
def current_object
model.find(params[:id])
end
def current_object_var_name
"@#{model_name.underscore}"
end
除了总是使用@object
或类似的东西之外,我看不到使用实例变量\u get/set
的快捷方法。但如果您不想这样做,那么这些行现在就简单一点:
instance_variable_set current_object_var_name, current_object
obj = instance_variable_get(current_object_var_name)
在这一点上,您的代码应该更具可读性,并且更加美观
您可能还想了解一些最新的Rails授权插件正在做什么,特别是。结合您的两个答案,我留下了以下相当干净的代码,我真的应该将其放入一个单独的插件中
private
def get_resource
begin
instance_variable_set current_object_var_name.to_sym, model_name.constantize.find(params[:id])
rescue
flash[:error] = "You do not have access to that #{model_name}."
redirect_to "/" and return
end
end
def require_owner
unless resource.user == current_user
flash[:error] = "You do not have access to that #{model_name}."
redirect_to "/" and return
end
end
def require_access
unless current_user.has_access?(resource)
flash[:error] = "You do not have access to that #{model_name}."
redirect_to "/" and return
end
end
def resource
instance_variable_get(current_object_var_name)
end
def model_name
@model_name ||= controller_name.classify
end
def current_object_var_name
"@#{model_name.underscore}"
end
结合你的两个答案,我留下了以下相当干净的代码,我真的应该把它们放在一个单独的插件中
private
def get_resource
begin
instance_variable_set current_object_var_name.to_sym, model_name.constantize.find(params[:id])
rescue
flash[:error] = "You do not have access to that #{model_name}."
redirect_to "/" and return
end
end
def require_owner
unless resource.user == current_user
flash[:error] = "You do not have access to that #{model_name}."
redirect_to "/" and return
end
end
def require_access
unless current_user.has_access?(resource)
flash[:error] = "You do not have access to that #{model_name}."
redirect_to "/" and return
end
end
def resource
instance_variable_get(current_object_var_name)
end
def model_name
@model_name ||= controller_name.classify
end
def current_object_var_name
"@#{model_name.underscore}"
end
哦,太好了,这些确实很好用。仅此而已,它应该是
controller\u name.gsub(“controller”,”)。分类
对吗?嗯……在我的controllers中,controller\u name
方法为您去掉了“controller”一词。换句话说,如果控制器是fastcarscocontroller
,则controller\u name
返回字符串“fast\u cars”
。试着把它放在一个视图中:
,看看它到底给你带来了什么。哦,我明白了。在过去,我使用了params[:controller],但我没有意识到controller_name并没有产生相同的结果。哦,太好了,这些确实工作得很好。仅此而已,它应该是controller\u name.gsub(“controller”,”)。分类
对吗?嗯……在我的controllers中,controller\u name
方法为您去掉了“controller”一词。换句话说,如果控制器是fastcarscocontroller
,则controller\u name
返回字符串“fast\u cars”
。试着把它放在一个视图中:
,看看它到底给你带来了什么。哦,我明白了。在过去,我使用了params[:controller],但我没有意识到controller_name不会产生相同的结果。