2013-10-07 49 views
0

我跟隨tutorial並有user,hotelrating模型。用戶可以創建酒店,用戶可以對它們評分。用戶評分值連同user_idhotel_id一起記錄在表rating中。當我渲染部分<%= render "hotels/hotels_list", :@hotels => Hotel.all %>它顯示的酒店列表以及它們平均評分模型計算hotel 型號Hotel.rb:表格列自動計算平均評分

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 

型號User.rb:

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

型號Rating.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 

回答

2

很簡單。首先,您將通過遷移將average_rating列添加到您的酒店模型中。然後,您將爲您的評分模型添加回調,該模型會更新酒店模型中的值。基本上,每次創建,銷燬或更新評分時,都需要更新平均評分。它看起來像這樣:

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 

現在你可以很容易地通過評級排序。我將留下一些細節,但我認爲你可以在這裏得到一般想法。

0

在例如通過@muffinista你應該做更多的「紅寶石十歲上下」,並做一個單行:

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