我是Rails的新手(我曾在MVC工作,但没有那么多)而且我正在尝试以“正确”的方式做事,但我在这里有点困惑。
我有一个带过滤器的网站导航按不同标准的项目,意思是:
Items.popular
Items.recommended
User.items
Brand.items # by the parent brand
Category.items # by a category
问题是我不知道如何在控制器中处理这个问题,其中每个操作对每个项目集合执行类似的逻辑(例如,存储在会话中并响应JS)
我在每个过滤器(大型控制器)或的ItemsController
中都有一个操作我将其放入ItemsController
BrandsController
,CategoriesController
(重复逻辑),但都没有提供“干净”的控制器。
但我不知道女巫哪个更好,或者我应该做别的事情。
提前致谢!
答案 0 :(得分:2)
你问两个不同的问题。 Items.popular
和Items.recommended
最好在Item
模型中作为named scope实现。这将Xavier推荐的模型抽象出来。然后在ItemsController
中,你会有类似
def popular
@items = Item.popular
end
def recommended
@items = Item.recommended
end
这与Xavier推荐的功能不同,但对我来说,这更容易理解。 (我总是试着为我的版本编写我的代码,这些代码将在六个月后出现,以便不知道键盘上的那个人在想什么。)
你问的第二件事是关于nested resources。假设您的代码类似于:
class User
has_many :items
end
然后您可以通过包含
将用户路由到该用户的项目resources :users do
resources :items
end
在routes.rb文件中。重复其他嵌套资源。
你说的最后一件事是
问题在于我不知道如何在控制器中处理这个问题,每个操作对每个项目集合执行类似的逻辑(例如,存储在会话中并响应js)
如果我上面说过的话并没有为你解决这个问题(我认为除非有一篇文章你已经遗漏了。)这听起来像是一个子类化的例子。将公共代码放在超类中,在子类中执行特定的操作并调用super
。
答案 1 :(得分:1)
有一种非常方便的方法来处理这个问题,实际上 - 你只需要小心并清理事物,因为它涉及从浏览器获取非常靠近数据库的输入。基本上,在ItemsController
中,你有一个看起来很像这样的函数:
def search
@items = Item.where(params[:item_criteria])
end
可怕,不是吗?但有效!为安全起见,我建议使用以下内容:
def search
searchable_attrs = [...] #Possibly load this straight from the model
conditions = params[:item_criteria].keep_if do |k, v|
searchable_attrs.contains? k
end
conditions[:must_be_false] = false
@items = Item.where(conditions)
end
前四行曾经可以使用ActiveSupport的Hash#slice方法,但已被弃用。我假设某个地方有新版本,因为它非常有用,但我不确定它是什么。
希望有所帮助!
答案 2 :(得分:1)
我认为两个答案(@ Xaviers和@jxpx777)都很好,但应该在不同情况下使用。如果你的观点对于热门和推荐的项目完全相同,那么我认为你应该对它们使用相同的动作。特别是如果这只是一种过滤索引页面的方法,并且您想要一种同时过滤推荐项目和热门项目的方法。或者也许属于特定用户的热门项目?但是,如果视图不同,那么您也应该使用不同的操作。
这同样适用于嵌套资源(用户,品牌和类别的项目)。因此,完整的索引操作可能如下所示:
# Items controller
before_filter :parent_resource
def index
if @parent
@items = @parent.items
else
@items = Item.scoped
end
if params[:item_criteria]
@items = @items.where(params[:item_criteria])
end
end
private
def parent_resource
@parent = if params[:user_id]
User.find(params[:user_id])
elsif params[:brand_id]
Brand.find(params[:brand_id])
elsif params[:category_id]
Category.find(params[:category_id])
end
end