想像你有两条定义的路线:
map.resources articles map.resources categories,:has_many => :articles
都可以通过助手/路径访问
articles_path # /articles category_articles_path(1) # /category/1/articles
如果您访问/文章,则执行ArticleController中的索引操作.
如果你访问/ category / 1 / articles,ArticleController的索引操作也被执行.
那么,根据呼叫路由,有条件地仅选择作用域文章的最佳方法是什么?
#if coming from the nested resource route @articles = Articles.find_by_category_id(params[:category_id]) #else @articles = Articles.all
解决方法
您有两种选择,具体取决于您的逻辑和视图与范围的关系.
让我进一步解释.
让我进一步解释.
第一个选择是确定您的控制器中的范围,如其他响应已经说明的.我通常设置一个@scope变量,以在我的模板中获得一些额外的好处.
class Articles before_filter :determine_scope def index @articles = @scope.all # ... end protected def determine_scope @scope = if params[:category_id] Category.find(params[:category_id]).articles else Article end end end
@scope变量的原因是您可能需要在单个操作之外了解请求的范围.假设您要显示视图中的记录数.您需要知道您是否按类别进行过滤.在这种情况下,您只需要调用@ scope.count或@ scope.my_named_scope.count,而不是每次对params [:category_id]进行检查时重复.
如果您的观点,类别和无类别的观点非常相似,则此方法效果很好.但是,按照类别筛选的列表与没有类别的列表完全不同,会发生什么?这经常发生:您的类别部分提供了一些类别关注的小部件,而您的文章部分则是与文章相关的小部件和过滤器.此外,您的文章控制器有一些特殊的before_filters可能需要使用,但是当文章列表属于一个类别时,您不必使用它们.
在这种情况下,您可能需要分离操作.
map.resources articles map.resources categories,:collection => { :articles => :get } articles_path # /articles and ArticlesController#index category_articles_path(1) # /category/1/articles and CategoriesController#articles
现在按类别过滤的列表由CategoriesController管理,它继承了所有控制器过滤器,布局,设置…,而未过滤的列表由ArticlesController管理.
这通常是我最喜欢的选择,因为通过额外的操作,您不必用大量的条件检查来混淆您的观点和控制器.