如何一次对两个级别的关联属性进行排序?

时间:2013-06-23 14:37:58

标签: ruby-on-rails

我相信这是一个简单的红宝石问题。在我的应用程序中,我有产品型号has_many评论。每个评论都有一个“整体”评级属性,它是一个整数。

我想要做的是根据其总体评分的平均值显示前十个产品。我已经让这个工作了,但是,我也想要通过辅助聚合属性对具有相同整体评级的产品进行排序,这将是许多人对产品的评论。现在,如果我有3个产品具有相同的平均总体评级,它们似乎以随机顺序显示。

到目前为止,我的代码是:

控制器

@best = Product.has_reviews.get_best_products(10)

产品型号

scope :has_reviews, joins{reviews.outer}.where{reviews.id != nil}

def self.get_best_products(number)
  sorted = self.uniq
  sorted = sorted.sort { |x, y| y.reviews.average("overall").to_f <=> x.reviews.average("overall").to_f }
  sorted.first(number)
end

我为我的模型代码尝试了这个:

def self.get_best_products(number)
  sorted = self.uniq.sort! { |x, y| x.reviews.count.to_f <=> y.reviews.count.to_f }
  sorted = sorted.sort { |x, y| y.reviews.average("overall").to_f <=> x.reviews.average("overall").to_f }
  sorted.first(number)
end

......但它没有做我想做的事。我只是在我的视图中使用每个数组迭代@best数组。

--- UPDATE

好的,我现在正在尝试这个:

控制器:

@best = Product.get_best_products(6)

型号:

def self.get_best_products(number)
  self.joins{reviews}.order{'AVG(reviews.overall), COUNT(reviews)'}.limit(number)
end

但是我收到了这个错误:

PGError: ERROR:  column "products.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT  "products".* FROM "products" INNER JOIN "reviews" ...

我正在使用Squeel gem btw来避免在模型中使用直接的SQL代码。

----更新2

现在我将'group'部分添加到我的方法中,但我仍然收到错误:

def self.get_best_products(number)
  self.joins{reviews}.group('product.id').order{'AVG(reviews.overall), COUNT(reviews)'}.limit(number)
end

我收到此错误:

PGError: ERROR:  missing FROM-clause entry for table "product"
LINE 1: ...eviews"."product_id" = "products"."id" GROUP BY product.i...

2 个答案:

答案 0 :(得分:0)

<强> product.rb

scope :best_products, (lambda do |number|
  joins(:reviews).order('AVG(reviews.overall), COUNT(reviews)').limit(number)
)

<强> products_controller.rb

Product.best_products(10)

这可确保数据库中的所有内容都发生,因此您将无法获得不需要的记录。

答案 1 :(得分:0)

如果我说得对,我的想法就是如何做到这一点:

由于products有许多reviewsreviewsoverall属性,我会在product表中添加reviews_counter列,每增加一列审核,这样您就可以获得更多的数据库性能,因为您无需count所有products次评论,即可获得评分最高的评分。

现在,您将获得reviews_counter订购的产品:

@best_products = Products.order("reviews_counter desc")

接下来,您将获得reviews订购的每件商品的overall

<% for prod in @best_products %>
  <%= prod.reviews.order("overall desc") %> # can do all this or more in helper
<% end %>

也按这种方式订购,如果您有3条评论总体相同,则可以再添加一条order()语句,并按nameid或您喜欢的任何内容对其进行排序,以便他们不要t以随机顺序显示。

这只是我对如何做到这一点的想法,我最近在一个需要类似东西的应用程序上工作,我们只是在我们的模型中添加了一个counter_field,这样做并不违法:)

P.S。我不太清楚你想要为每个记录显示多少记录,所以你只需要添加.limit(5)例如只获得产品的前5个评论。