Ruby Rails元编程/重构/干燥控制器
我有一个控制器,有几个动作。许多人遵循这一模式:Ruby Rails元编程/重构/干燥控制器,ruby,ruby-on-rails-4,metaprogramming,Ruby,Ruby On Rails 4,Metaprogramming,我有一个控制器,有几个动作。许多人遵循这一模式: def favorites @favorites = Favorite.where(organization_id: @resource.id).page(params[:page]).per(50) end 它不仅是收藏夹,还有下载、搜索、列表等,它们都非常相似,我想创建一个方法,可以在before_过滤器中调用。大概是这样的: def set_instance_variable subject = __method__ clas
def favorites
@favorites = Favorite.where(organization_id: @resource.id).page(params[:page]).per(50)
end
它不仅是收藏夹,还有下载、搜索、列表等,它们都非常相似,我想创建一个方法,可以在before_过滤器中调用。大概是这样的:
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
class FavoritesController
load_resource
paginate_resource only: [:index]
def show
# @favorite loaded here
end
def index
# @favorites loaded and paginated here
end
end
def favorites
@favorites = load_resource Favorite
end
private
def load_resource(klass)
klass.where(organization_id: @resource.id).page(params[:page]).per(50)
end
这里的语法可能有点不对劲,但我知道这不起作用,因为\uuuuuuuuuuuuuuuuuuuuuuu方法
总是设置为\u instance\u变量,而不是调用它的父方法
有没有一种方法可以根据定义实例变量的方法动态设置它们?上面的例子正确吗?我喜欢CanCan库处理这个问题的方式。使用CanCan,您可以调用控制器顶部的类方法:
load_resource
坎坎接着看:
- 用于确定是否需要集合或单一资源的操作
- 用于确定要加载的类的控制器的名称
- 用于添加范围的授权规则,如您的组织\u id限制(cancan也是定义这些范围的库)
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
class FavoritesController
load_resource
paginate_resource only: [:index]
def show
# @favorite loaded here
end
def index
# @favorites loaded and paginated here
end
end
def favorites
@favorites = load_resource Favorite
end
private
def load_resource(klass)
klass.where(organization_id: @resource.id).page(params[:page]).per(50)
end
如果在应用程序中使用非restful资源更有意义,那么就不能重复使用基于约定的cancan,而必须定义自己的函数。考虑这样的事情:
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
class FavoritesController
load_resource
paginate_resource only: [:index]
def show
# @favorite loaded here
end
def index
# @favorites loaded and paginated here
end
end
def favorites
@favorites = load_resource Favorite
end
private
def load_resource(klass)
klass.where(organization_id: @resource.id).page(params[:page]).per(50)
end
嗯,很有趣。我会调查的。一个紧迫的问题是,所有这些操作都在OrganizationsController中,而不是FavoritesController中。这不是一个典型的脚手架控制器,这可能增加了问题。也许这和坎坎没关系?好吧,如果你遵循标准惯例,干涸和重复使用东西是最容易的。收藏夹资源通常是收藏夹控制器的索引操作,而不是另一个控制器中单独的非restful资源。谢谢。这是一个很好的妥协。我必须为每个操作设置实例变量,但至少它看起来更像是一个较小的行。也许基于动作猜测类名并将其放入before过滤器过于复杂了。我可以接受这个解决方案。看起来
与我有很多关联(特别是你在下面提到的组织控制器)。如果您定义了它,您将能够在筛选之前在中设置@resource
(@organization
),然后调用@resource.favorites
,@resource.downloads
等。