- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一些之前的过滤器,用于在逐个资源级别上控制对资源的访问。基本思路如下:
user
或 admin
,并且可以访问基于“accesses”表的特定资源。admin
、owner
、特定用户或所有人。一些代码示例可以很好地说明这一点。我们有 4 个应用程序级方法,它们使用 before_filter
添加到调用链中。这是示例 Controller 类的顶部:
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]
如您所见,首先我们要求用户登录才能访问此 Controller 中的任何方法。这里有 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}")
或
instance_variable_set "@#{class_name}".to_sym, class_name.capitalize.constantize.find(params[:id])
有谁知道我在这里做的事情有更优雅的方式吗?
最佳答案
我不知道是否有真正干净的方法来做到这一点,但这里有一些建议:
首先,创建一个 Controller ResourceController
,并让所有相关的 Controller 继承自它。 (如果此授权适用于所有 Controller ,您可以只使用 ApplicationController
。)
现在,在名为 model_name
的父类(super class)中实现一个私有(private)方法(就像您的 class_name
)这样您就不必在每次需要时都派生它。 并且,您应该能够通过简单地执行以下操作来推导出它:
def model_name
controller_name.classify
end
您还可以在返回实际类的父类(super class)中实现 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
或类似的东西之外,我没有看到使用 instance_variable_get/set
的快速方法。但如果您不想这样做,这些行现在更简单了一些:
instance_variable_set current_object_var_name, current_object
obj = instance_variable_get(current_object_var_name)
此时您的代码应该更具可读性,也更漂亮一些。
您可能还想查看一些最近的 Rails 授权插件在做什么,特别是 cancan和 declarative_authorization .
关于ruby-on-rails - 让通用的 before_filters 不那么难看?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1929782/
我是一名优秀的程序员,十分优秀!