我有一个带有多个动作的控制器。许多人遵循这种模式:
def favorites
@favorites = Favorite.where(organization_id: @resource.id).page(params[:page]).per(50)
end
这不仅仅是收藏夹,而且还有下载,搜索,列表等,它们都非常相似,我想创建一个我可以在before_filter中调用的方法。像这样:
def set_instance_variable
subject = __method__
class = __method__.singularize.constantize
instance_variable = self.class.instance_variable_set("@#{subject}", "#{class}.where(organization_id: @resource.id).page(params[:page]).per(50)")
end
这里的语法可能有些偏差,但我知道这不起作用,因为__method__
将始终是set_instance_variable而不是调用它的父方法。
有没有办法根据定义它们的方法动态设置实例变量?上面这个例子是否在正确的轨道上?
答案 0 :(得分:1)
我喜欢CanCan库处理这个问题的方式。使用CanCan,您可以在控制器顶部调用类方法:
load_resource
CanCan然后看:
您决定是否需要收藏品或单一资源的行动,
用于确定要加载的类的控制器的名称
添加范围的授权规则,例如您的organization_id限制(cancan也是用于定义这些范围的库)
我认为分页和资源加载是分开的,你不应该把它们放在同一个方法中。我正在拍摄这样的界面:
class FavoritesController
load_resource
paginate_resource only: [:index]
def show
# @favorite loaded here
end
def index
# @favorites loaded and paginated here
end
end
https://github.com/CanCanCommunity/cancancan/blob/develop/lib/cancan/controller_resource.rb#L29
如果在您的应用程序中使用非平静资源更有意义,那么您无法重新使用基于约定的事物cancan,而是必须定义您自己的函数。考虑这样的事情:
def favorites
@favorites = load_resource Favorite
end
private
def load_resource(klass)
klass.where(organization_id: @resource.id).page(params[:page]).per(50)
end