Module: Mongoid::Rating::Model::ClassMethods
- Defined in:
- lib/mongoid_rating/model.rb
Instance Method Summary collapse
-
#rateable(field, opt = {}) ⇒ Object
Make model rateable.
Instance Method Details
#rateable(field, opt = {}) ⇒ Object
Make model rateable
rateable :overall, range: -5..5
Disable average completely rateable :design, range: -5..5, average: false rateable :quality, range: -5..5, average: true
float: whether to allow non-integer rates (default true)
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/mongoid_rating/model.rb', line 19 def rateable(field, opt = {}) = { range: 1..5, rerate: true, counters: true, float: true, }.merge(opt) [:no_rate] ||= [:float] ? '0.0' : '0' [:format] ||= [:float] ? '%.1f' : '%d' field = field.to_sym sfield = field.inspect # total rates count field "#{field}_count", type: Integer, default: 0 # rates data "#{field}_data", as: :rateable, class_name: 'Mongoid::Rating::Rate', counter_cache: true # sum of all rates to calculate average field "#{field}_sum".to_sym, type: [:float] ? Float : Integer # average rate value avg = "#{field}_average".to_sym field avg, type: Float savg = avg.inspect class_eval <<-RUBY, __FILE__, __LINE__+1 scope :#{field}_by, ->(rater) { where("#{field}_data.rater_id" => rater.id, "#{field}_data.rater_type" => rater.class.to_s) } scope :#{field}_in, ->(range) { where(#{savg}.gte => range.begin, #{savg}.lte => range.end) } scope :by_#{field}, -> { order_by([#{savg}, :desc]) } scope :highest_#{field}, -> { where(#{savg}.ne => nil).order_by([#{savg}, :desc]) } # return user's rate if rated otherwise formatted rate value # good for Raty JS plugin def fmt_#{field}(user = nil) if !user.nil? && #{field}_by?(user) #{[:format].inspect} % #{field}_by(user) elsif #{field}.nil? #{[:no_rate].class.name == 'String' ? [:no_rate].inspect : [:no_rate]} else #{[:format].inspect} % #{field} end end def #{field}!(value, rater) if #{[:float]} value = value.to_f else value = value.to_i end unless (#{[:range]}).include?(value) raise "bad vote value" end raise "can't rate" unless can_#{field}?(rater) un#{field}!(rater) atomically do inc("#{field}_count" => 1, "#{field}_sum" => value) #{field}_data.create!(rater: rater, value: value) set("#{field}_average" => calc_#{field}_avg) end end def calc_#{field}_avg if #{field}_count < 1 nil else #{field}_sum.to_f / #{field}_count.to_f end end def un#{field}!(rater) r = #{field}_data.where(rater_id: rater.id).first if r.nil? # not rated before else atomically do inc("#{field}_count" => -1, "#{field}_sum" => -r.value) set("#{field}_average" => calc_#{field}_avg) r.destroy end end end alias_method :un#{field}, :un#{field}! def did_#{field}?(rater) !raw_#{field}_by(rater).nil? end def can_#{field}?(rater) if #{[:rerate]} true else !did_#{field}?(rater) end end def raw_#{field}_by(rater) #{field}_data.select do |rate| rate[:rater_id] == rater.id && rate[:rater_type] == rater.class.name end.first end def #{field}(value=nil, rater=nil) if rater.nil? && value.nil? #{field}_count.nil? ? nil : #{field}_average else #{field}!(value, rater) end end def #{field}_values #{field}_data.map(&:value) end def #{field}_by(rater) rate = raw_#{field}_by(rater) if rate.nil? nil else rate.value end end def #{field}_by?(rater) !#{field}_by(rater).nil? end RUBY end |