在Rails中组织站点导航操作

时间:2013-05-31 12:51:25

标签: ruby-on-rails ruby model-view-controller controller

我是Rails的新手(我曾在MVC工作,但没有那么多)而且我正在尝试以“正确”的方式做事,但我在这里有点困惑。

我有一个带过滤器的网站导航按不同标准的项目,意思是:

Items.popular  
Items.recommended

User.items

Brand.items # by the parent brand

Category.items # by a category

问题是我不知道如何在控制器中处理这个问题,其中每个操作对每个项目集合执行类似的逻辑(例如,存储在会话中并响应JS)

我在每个过滤器(大型控制器)ItemsController中都有一个操作我将其放入ItemsController BrandsControllerCategoriesController(重复逻辑),但都没有提供“干净”的控制器。

但我不知道女巫哪个更好,或者我应该做别的事情。

提前致谢!

3 个答案:

答案 0 :(得分:2)

你问两个不同的问题。 Items.popularItems.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