1

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

我有一个网站导航,其中包含不同标准的过滤器项目,这意味着:

Items.popular  
Items.recommended

User.items

Brand.items # by the parent brand

Category.items # by a category

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

ItemsController要么我对每个过滤器(大控制器)都有一个动作,要么把它放进去ItemsController BrandsControllerCategoriesController(重复逻辑),但都没有提供“干净”的控制器。

但我不知道女巫一个更好,或者我是否应该做点别的。

提前致谢!

4

3 回答 3

2

You're asking two separate questions. Items.popular and Items.recommended are best achieved in your Item model as a named scope This abstracts what Xavier recommended into the model. Then in your ItemsController, you'd have something like

def popular
    @items = Item.popular
end

def recommended
    @items = Item.recommended
end

This isn't functionally different than what Xavier recommended, but to me, it is more understandable. (I always try to write my code for the version of me that will come to it in six months to not wonder what the guy clacking on the keyboard was thinking.)

The second thing you're asking is about nested resources. Assuming your code reads something like:

class User
    has_many :items
end

then you can route through a user to that user's items by including

resources :users do
    resources :items
end

in your routes.rb file. Repeat for the other nested resources.

The last thing you said is

The problem is that I don't know how to deal with this in the controller, where each action does a similar logic for each collection of items (for example, store in session and respond to js)

If what I've said above doesn't solve this for you (I think it would unless there's a piece you've left out.) this sounds like a case for subclassing. Put the common code in the superclass, do the specific stuff in the subclass and call super.

于 2013-05-31T13:44:57.570 回答
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方法,但已被弃用。我假设某处有一个新版本,因为它非常有用,但我不确定它是什么。

希望有帮助!

于 2013-05-31T13:32:33.870 回答
1

I think both answers(@Xaviers and @jxpx777's) is good but should be used in different situations. If your view is exactly the same for popular and recommended items then i think you should use the same action for them both. Especially if this is only a way to filter your index page, and you want a way to filter for both recommended and popular items at the same time. Or maybe popular items belonging to a specific users? However if the views are different then you should use different actions too.

The same applies to the nested resource (user's, brand's and category's items). So a complete index action could look something like this:

# 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
于 2013-05-31T14:24:21.223 回答