我正在关注tutorial并拥有模型user
,hotel
和rating
。用户可以创建酒店,用户可以对其进行评级。用户评分值与rating
和user_id
一起记录到表格hotel_id
。当我呈现部分<%= render "hotels/hotels_list", :@hotels => Hotel.all %>
时,它会显示在模型hotel
中计算的平均评分的酒店列表
Model 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
Model 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
答案 0 :(得分: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
现在您可以轻松按评分排序。我要留下一些细节,但我想你可以在这里得到一般的想法。
答案 1 :(得分:0)
在@muffinista的例子中,你应该做的更多&#39; Ruby-ish&#39;并在一行中完成:
def update_average_rating
update_attributes(average_rating: self.ratings.collect(&:value).avg)
end
如果您希望nil
,则可以.compact.avg
。
您需要使用#avg扩展Array:
class Array
def avg
sum.to_f/size
end
end