如何按平均评分对记录进行排序? [英] How can I sort my records by average rating?

查看:107
本文介绍了如何按平均评分对记录进行排序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个场所表,我将其作为部分显示在场所索引页面上.我也有一张评论表,其中一个场地可以有很多评论,每条评论的评分为1-5.

I have a table of venues which I'm displaying on the venues index page as partials. I also have a table of reviews where one venue can have many reviews and each review has a rating 1-5.

我正试图让这些场所显示在索引页面上,其中平均评分最高的场所在顶部和底部.

I'm trying to get the venues to display on the index page with the ones with the highest average rating at the top and descending.

控制器代码如下:

场地控制器

def index
    if
      @venues = Venue.with_type(params[:venuetypes]).with_area(params[:areas]).joins(:reviews).order("reviews.rating DESC")
    else
      @venues = Venue.all
    end
  end

这给出了这样的结果:

  • 如果场所1拥有5星评价 显示场地的局部 列表.

  • If venue 1 has a 5 star review it shows the venue partial at the top of the list.

如果场所2拥有5星评价,并且 一个1星级的评论显示其中两个 部分,顶部一个,另一个
在列表的底部.

If venue 2 has a 5 star review and a 1 star review it shows two partials, one at the top and one
at the bottom of the list.

如果场所3拥有5星评论,则获得3星评论,并且 1星评价它表明三 局部,顶部一个,中间一个,一个 在列表的底部.

If venue 3 has a 5 star review, a 3 star review and a 1 star review it shows three partials, one at the top, one in the middle and one at the bottom of the list.

我只希望每个场馆进行部分放映,但按平均评分位于列表中,我觉得在某个地方缺少.average或某些东西该怎么办?

I just want one partial showing per venue but positioned in the list by the average rating, I feel theres a .average or something missing somewhere how can I acheive this?

非常感谢您的帮助!

修改

场地模型

class Venue < ActiveRecord::Base
  attr_accessible :name, :addressline1, :addressline2, :addressline3, :addressline4, :postcode, :phonenumber, :about, :icontoppx, :iconleftpx, :area_id, :venuetype_id, :lat, :long, :venuephotos_attributes
  belongs_to :area
  belongs_to :venuetype
  has_many :reviews
  has_many :venuephotos

  accepts_nested_attributes_for :venuephotos, :allow_destroy => true

  scope :with_type, lambda { |types|
    types.present? ? where(:venuetype_id => types) : scoped }

  scope :with_area, lambda { |areas|
    areas.present? ? where(:area_id => areas) : scoped }

  def to_param
    "#{id}-#{name.gsub(/\W/, '-').downcase}"
  end

  def add_rating(rating_opts)
    @venue.add_rating(:rating => rating, :reviewer => params[:rating][:reviewer])
    self.reviews.create(rating_opts)
    self.update_rating!
  end

  def update_rating!
    s = self.reviews.sum(:rating)
    c = self.reviews.count
    self.update_attribute(:average_rating, s.to_f / c.to_f)
    self.save(:validate => false)
  end
end

用于添加评论的开发日志

Started POST "/venues/44-rating-test-5/reviews" for 127.0.0.1 at 2011-05-18 09:24:24 +0100
  Processing by ReviewsController#create as JS
  Parameters: {"utf8"=>"âœ"", "authenticity_token"=>"GZWd67b5ocJOjwKI6z9nJInBXxvQahHrjUtUpdm9oJE=", "review"=>{"rating"=>"5", "title"=>"5 star review"}, "venue_id"=>"44-rating-test-5"}
  [1m[36mVenue Load (1.0ms)[0m  [1mSELECT `venues`.* FROM `venues` WHERE (`venues`.`id` = 44) LIMIT 1[0m
  [1m[35mUser Load (0.0ms)[0m  SELECT `users`.* FROM `users` WHERE (`users`.`id` = 3) LIMIT 1
  [1m[36mSQL (0.0ms)[0m  [1mBEGIN[0m
  [1m[35mSQL (2.0ms)[0m  describe `reviews`
  [1m[36mAREL (0.0ms)[0m  [1mINSERT INTO `reviews` (`title`, `created_at`, `updated_at`, `venue_id`, `user_id`, `rating`) VALUES ('5 star review', '2011-05-18 08:24:24', '2011-05-18 08:24:24', NULL, 3, 5)[0m
  [1m[35mSQL (27.0ms)[0m  COMMIT
  [1m[36mSQL (0.0ms)[0m  [1mBEGIN[0m
  [1m[35mAREL (0.0ms)[0m  UPDATE `reviews` SET `venue_id` = 44, `updated_at` = '2011-05-18 08:24:24' WHERE (`reviews`.`id` = 90)
  [1m[36mSQL (23.0ms)[0m  [1mCOMMIT[0m
  [1m[35mSQL (1.0ms)[0m  SELECT COUNT(*) FROM `reviews` WHERE (`reviews`.venue_id = 44)
  [1m[36mUser Load (0.0ms)[0m  [1mSELECT `users`.* FROM `users` WHERE (`users`.`id` = 3) LIMIT 1[0m
Rendered reviews/_review.html.erb (9.0ms)
Rendered reviews/create.js.erb (22.0ms)
Completed 200 OK in 220ms (Views: 56.0ms | ActiveRecord: 54.0ms)

修改 创建评论方法(评论控制器)

def create
    @review = current_user.reviews.create!(params[:review])
    @review.venue = @venue
    if @review.save
      flash[:notice] = 'Thank you for reviewing this venue!'
      respond_to do |format|
        format.html { redirect_to venue_path(@venue) }
        format.js
      end
    else
      render :action => :new
    end
  end

推荐答案

要添加到

To add to NoICE's answer, by hooking into the :after_add and :after_remove association callbacks, you don't have to remember to call a special add_rating method.

class Venue < ActiveRecord::Base
  has_many :reviews, :after_add => :update_average_rating, :after_remove => :update_average_rating

  def update_average_rating(review=nil)
    s = self.reviews.sum(:rating)
    c = self.reviews.count
    self.update_attribute(:average_rating, c == 0 ? 0.0 : s / c.to_f)
  end

end

此外,您还需要检查count的值是否为0,以防止被零除.

Also, you'll want to check count for 0 to prevent division by zero.

创建审阅时,必须将其添加<<concat到场地对象的reviews关联中,以便触发回调.例如,这会将评论与场所相关联,创建评论(将INSERT插入数据库),并触发回调:

When you create the review, you must append with << or concat it to the venue object's reviews association so that the callback gets triggered. For example, this will associate the review to the venue, create the review (INSERT into the db), and trigger the callback:

@venue = Venue.find(params[:venue_id])
@venue.reviews << Review.new(params[:review])

这将创建评论,但不会触发回调,即使venue_id是参数也是如此:

This will create the review but won't trigger the callback, even if the venue_id is the params:

Review.create(params[:review])

如果您确实想执行触发回调的操作,则可以将代码更改为:

If you really want to get your action to trigger the callback, you can change your code to:

def create
  @review = Review.new(params[:review].merge({ :user => current_user, :venue => @venue })
  if @review.valid? and @venue.reviews << @review
  ...

不过,为了方便地进行修复,您可以在带有flash[:notice]的行之前添加@review.venue.update_average_rating.

To fix it expediently, though, you could just add @review.venue.update_average_rating just before the line w/ flash[:notice].

这篇关于如何按平均评分对记录进行排序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆