【问题标题】:Organizing site navigation actions in Rails在 Rails 中组织站点导航操作
【发布时间】:2013-05-27 07:12:09
【问题描述】:

我是 Rails 的新手(我曾在 MVC 中工作过,但不是很多),我正在尝试以“正确”的方式做事,但我在这里有点困惑。

我有一个网站导航,其中包含按不同标准过滤项目,意思是:

Items.popular  
Items.recommended

User.items

Brand.items # by the parent brand

Category.items # by a category

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

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

但我不知道女巫一个更好,或者我是否应该做其他事情。

提前致谢!

【问题讨论】:

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


【解决方案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 方法,但已被弃用。我假设某处有一个新版本,因为它非常有用,但我不确定它是什么。

希望有帮助!

【讨论】:

  • 我不喜欢这个想法,但我把它介绍给我的同事/老板,他很害怕^^
  • @Nico - 够公平的!当我这样做时,我们需要组合过滤器的能力,并且命名范围有点笨拙,但我喜欢 jxpx 的版本将所有逻辑拉入模型中。我认为你做出了正确的选择。
【解决方案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

【讨论】:

  • 这可能是我正在寻找的,但最后一个问题,嵌套资源操作应该去哪里?到user_items 行动?
  • 阅读嵌套资源路由。通过将其添加到您的路线中,您将获得类似 http://mysite.com/users/[identifier]/items 和类似 user_items_url(@some_user_object) 的帮助程序来为您生成 URL。不需要控制器操作。
  • 我问是因为这意味着我必须知道要使用的女巫标识符(例如 params[:user_id]params[:category_id] )所以我会有很多 if (我肯定会好好阅读无论如何,谢谢)
  • 就像我说的,我可能会错过故事的某些部分。是的,您将需要 ItemsController 来检查这些参数,但是除了您请求帮助解决的场景之外,还有什么替代方案?
  • 抱歉不一致。只是意味着我将有 BrandsCategory 如问题所示指向相同的操作,我必须区分这两个标识符。
【解决方案3】:

我认为这两个答案(@Xaviers 和@jxpx777's)都很好,但应该在不同的情况下使用。如果您对热门商品和推荐商品的看法完全相同,那么我认为您应该对它们都使用相同的操作。尤其是如果这只是一种过滤索引页面的方法,并且您想要一种同时过滤推荐项目和热门项目的方法。或者可能属于特定用户的热门商品?但是,如果视图不同,那么您也应该使用不同的操作。

这同样适用于嵌套资源(用户、品牌和类别的项目)。所以一个完整的索引操作可能看起来像这样:

# 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

【讨论】:

  • 这看起来更像我现在拥有的。 parent_resource 是我关心的问题,因为我对 Rails 了解不多,而那些 ifs 吓到了我。
  • 当然不是太漂亮了,也许你应该考虑使用私有搜索方法来重构一下。然而,使用嵌套资源的最常见方法是在父显示操作中显示它们。例如,在该用户的显示/个人资料页面上显示用户项目。
猜你喜欢
  • 2020-07-15
  • 2011-11-27
  • 1970-01-01
  • 2013-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多