0

我正在学习教程并有模型userhotel并且rating. 用户可以创建酒店,用户可以对其进行评分。用户评分值与和rating一起记录到表中。当我渲染部分时,它显示了在模型Model Hotel.rb中计算的平均评级的酒店列表:user_idhotel_id<%= render "hotels/hotels_list", :@hotels => Hotel.all %>hotel

class Hotel < ActiveRecord::Base
  attr_accessible :user_id
  belongs_to :user
  has_many :ratings
  has_many :raters, :through => :ratings, :source => :users

  def average_rating
    @value = 0
    self.ratings.each do |rating|
      @value = @value + rating.value
    end
    @total = self.ratings.size
    '%.2f' % (@value.to_f / @total.to_f)
  end
end

模型用户.rb:

class User < ActiveRecord::Base
  has_many :hotels
  has_many :ratings
  has_many :rated_hotels, :through => :ratings, :source => :hotels
end

模型评级.rb:

class Rating < ActiveRecord::Base
  attr_accessible :value
  belongs_to :user
  belongs_to :hotel
end

我需要按平均评分对酒店列表进行排序,可能需要添加一些列 ,以便像酒店模型中的average_rating该方法一样立即计算平均值average_rating,这样我就可以轻松访问它。我该如何解决这个问题? RatingsController.rb

class RatingsController < ApplicationController

      before_filter :authenticate_user!
      def create
        @hotel = Hotel.find_by_id(params[:hotel_id])
        @rating = Rating.new(params[:rating])
        @rating.hotel_id = @hotel.id
        @rating.user_id = current_user.id
        if @rating.save
          respond_to do |format|
            format.html { redirect_to hotel_path(@hotel), :notice => "Your rating has been saved" }
            format.js
          end
        end
      end

      def update
        @hotel = Hotel.find_by_id(params[:hotel_id])
        @rating = current_user.ratings.find_by_hotel_id(@hotel.id)
        if @rating.update_attributes(params[:rating])
          respond_to do |format|
            format.html { redirect_to hotel_path(@hotel), :notice => "Your rating has been updated" }
            format.js
          end
        end
      end 
    end
4

2 回答 2

2

非常简单。首先,您将average_rating通过迁移将该列添加到您的 Hotel 模型中。然后,您将向您的 Rating 模型添加一个回调,以更新 Hotel 模型中的值。基本上,每次创建、销毁或更新评级时,您都需要更新平均评级。它看起来像这样:

class Hotel < ActiveRecord::Base
  [ code snipped ]

  def update_average_rating
    @value = 0
    self.ratings.each do |rating|
      @value = @value + rating.value
    end
    @total = self.ratings.size


    update_attributes(average_rating: @value.to_f / @total.to_f)
  end
end

class Rating
  belongs_to :hotel
  after_create :update_hotel_rating

  def update_hotel_rating
    hotel.update_average_rating
  end
end

现在您可以轻松按评分排序。我遗漏了一些细节,但我认为你可以在这里得到大致的想法。

于 2013-10-07T01:22:25.827 回答
0

在@muffinista 的示例中,您可能应该更“Ruby-ish”并在一行中完成:

def update_average_rating
  update_attributes(average_rating: self.ratings.collect(&:value).avg)
end

如果你期望nil的你可以做到.compact.avg

您需要使用#avg 扩展数组:

class Array
  def avg
    sum.to_f/size
  end
end
于 2015-03-04T14:53:51.013 回答