yeshoua_crm 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/Rakefile +11 -0
 - data/lib/yeshoua_crm.rb +87 -0
 - data/lib/yeshoua_crm/acts_as_draftable/draft.rb +40 -0
 - data/lib/yeshoua_crm/acts_as_draftable/rcrm_acts_as_draftable.rb +154 -0
 - data/lib/yeshoua_crm/acts_as_list/list.rb +282 -0
 - data/lib/yeshoua_crm/acts_as_taggable/rcrm_acts_as_taggable.rb +350 -0
 - data/lib/yeshoua_crm/acts_as_taggable/tag.rb +81 -0
 - data/lib/yeshoua_crm/acts_as_taggable/tag_list.rb +111 -0
 - data/lib/yeshoua_crm/acts_as_taggable/tagging.rb +16 -0
 - data/lib/yeshoua_crm/acts_as_viewed/rcrm_acts_as_viewed.rb +274 -0
 - data/lib/yeshoua_crm/acts_as_votable/rcrm_acts_as_votable.rb +80 -0
 - data/lib/yeshoua_crm/acts_as_votable/rcrm_acts_as_voter.rb +20 -0
 - data/lib/yeshoua_crm/acts_as_votable/votable.rb +323 -0
 - data/lib/yeshoua_crm/acts_as_votable/vote.rb +28 -0
 - data/lib/yeshoua_crm/acts_as_votable/voter.rb +131 -0
 - data/lib/yeshoua_crm/assets_manager.rb +43 -0
 - data/lib/yeshoua_crm/currency.rb +439 -0
 - data/lib/yeshoua_crm/currency/formatting.rb +224 -0
 - data/lib/yeshoua_crm/currency/heuristics.rb +151 -0
 - data/lib/yeshoua_crm/currency/loader.rb +24 -0
 - data/lib/yeshoua_crm/helpers/external_assets_helper.rb +17 -0
 - data/lib/yeshoua_crm/helpers/form_tag_helper.rb +123 -0
 - data/lib/yeshoua_crm/helpers/tags_helper.rb +13 -0
 - data/lib/yeshoua_crm/helpers/vote_helper.rb +35 -0
 - data/lib/yeshoua_crm/liquid/drops/cells_drop.rb +86 -0
 - data/lib/yeshoua_crm/liquid/drops/issues_drop.rb +66 -0
 - data/lib/yeshoua_crm/liquid/drops/news_drop.rb +54 -0
 - data/lib/yeshoua_crm/liquid/drops/users_drop.rb +72 -0
 - data/lib/yeshoua_crm/liquid/filters/arrays.rb +177 -0
 - data/lib/yeshoua_crm/liquid/filters/base.rb +208 -0
 - data/lib/yeshoua_crm/money_helper.rb +65 -0
 - data/lib/yeshoua_crm/version.rb +3 -0
 - data/test/acts_as_draftable/draft_test.rb +29 -0
 - data/test/acts_as_draftable/rcrm_acts_as_draftable_test.rb +185 -0
 - data/test/acts_as_taggable/rcrm_acts_as_taggable_test.rb +345 -0
 - data/test/acts_as_taggable/tag_list_test.rb +34 -0
 - data/test/acts_as_taggable/tag_test.rb +72 -0
 - data/test/acts_as_taggable/tagging_test.rb +15 -0
 - data/test/acts_as_viewed/rcrm_acts_as_viewed_test.rb +47 -0
 - data/test/acts_as_votable/rcrm_acts_as_votable_test.rb +19 -0
 - data/test/acts_as_votable/rcrm_acts_as_voter_test.rb +14 -0
 - data/test/acts_as_votable/votable_test.rb +507 -0
 - data/test/acts_as_votable/voter_test.rb +296 -0
 - data/test/currency_test.rb +292 -0
 - data/test/liquid/drops/issues_drop_test.rb +34 -0
 - data/test/liquid/drops/news_drop_test.rb +38 -0
 - data/test/liquid/drops/projects_drop_test.rb +44 -0
 - data/test/liquid/drops/uses_drop_test.rb +36 -0
 - data/test/liquid/filters/arrays_filter_test.rb +24 -0
 - data/test/liquid/filters/base_filter_test.rb +63 -0
 - data/test/liquid/liquid_helper.rb +32 -0
 - data/test/models/issue.rb +14 -0
 - data/test/models/news.rb +3 -0
 - data/test/models/project.rb +8 -0
 - data/test/models/user.rb +11 -0
 - data/test/models/vote_classes.rb +33 -0
 - data/test/money_helper_test.rb +12 -0
 - data/test/schema.rb +121 -0
 - data/test/tags_helper_test.rb +29 -0
 - data/test/test_helper.rb +66 -0
 - data/test/vote_helper_test.rb +28 -0
 - data/yeshoua_crm.gemspec +28 -0
 - metadata +206 -0
 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module YeshouaCrm
         
     | 
| 
      
 2 
     | 
    
         
            +
              module ActsAsTaggable #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Tagging < ActiveRecord::Base #:nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  belongs_to :tag
         
     | 
| 
      
 5 
     | 
    
         
            +
                  belongs_to :taggable, :polymorphic => true
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  after_destroy :destroy_tag_if_unused
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  private
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def destroy_tag_if_unused
         
     | 
| 
      
 12 
     | 
    
         
            +
                    tag.destroy if Tag.destroy_unused && tag.taggings.count.zero?
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,274 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Copyright (c) 2008 Damian Martinelli
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 4 
     | 
    
         
            +
            # a copy of this software and associated documentation files (the
         
     | 
| 
      
 5 
     | 
    
         
            +
            # "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 6 
     | 
    
         
            +
            # without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 7 
     | 
    
         
            +
            # distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 8 
     | 
    
         
            +
            # permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 9 
     | 
    
         
            +
            # the following conditions:
         
     | 
| 
      
 10 
     | 
    
         
            +
            #
         
     | 
| 
      
 11 
     | 
    
         
            +
            # The above copyright notice and this permission notice shall be
         
     | 
| 
      
 12 
     | 
    
         
            +
            # included in all copies or substantial portions of the Software.
         
     | 
| 
      
 13 
     | 
    
         
            +
            #
         
     | 
| 
      
 14 
     | 
    
         
            +
            # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 15 
     | 
    
         
            +
            # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 16 
     | 
    
         
            +
            # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 17 
     | 
    
         
            +
            # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 18 
     | 
    
         
            +
            # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 19 
     | 
    
         
            +
            # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 20 
     | 
    
         
            +
            # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
| 
      
 21 
     | 
    
         
            +
            module YeshouaCrm
         
     | 
| 
      
 22 
     | 
    
         
            +
              module ActsAsViewed #:nodoc:
         
     | 
| 
      
 23 
     | 
    
         
            +
                # == acts_as_viewed
         
     | 
| 
      
 24 
     | 
    
         
            +
                # Adds views count capabilities to any ActiveRecord object.
         
     | 
| 
      
 25 
     | 
    
         
            +
                # It has the ability to work with objects that have or don't special fields to keep a tally of the
         
     | 
| 
      
 26 
     | 
    
         
            +
                # viewings for each object.
         
     | 
| 
      
 27 
     | 
    
         
            +
                # In addition it will by default use the User model as the viewer object and keep the viewings per-user.
         
     | 
| 
      
 28 
     | 
    
         
            +
                # It can be configured to use another class.
         
     | 
| 
      
 29 
     | 
    
         
            +
                # The IP address are used to not repeat views from the same ip. Only one view are count by user or IP.
         
     | 
| 
      
 30 
     | 
    
         
            +
                #
         
     | 
| 
      
 31 
     | 
    
         
            +
                # Special methods are provided to create the viewings table and if needed, to add the special fields needed
         
     | 
| 
      
 32 
     | 
    
         
            +
                # to keep per-objects viewings fast for access to viewed objects. Can be easily used in migrations.
         
     | 
| 
      
 33 
     | 
    
         
            +
                #
         
     | 
| 
      
 34 
     | 
    
         
            +
                # == Example of usage:
         
     | 
| 
      
 35 
     | 
    
         
            +
                #
         
     | 
| 
      
 36 
     | 
    
         
            +
                #   class Video < ActiveRecord::Base
         
     | 
| 
      
 37 
     | 
    
         
            +
                #     acts_as_viewed
         
     | 
| 
      
 38 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 39 
     | 
    
         
            +
                #
         
     | 
| 
      
 40 
     | 
    
         
            +
                #   In a controller:
         
     | 
| 
      
 41 
     | 
    
         
            +
                #
         
     | 
| 
      
 42 
     | 
    
         
            +
                #   bill = User.find_by_name 'bill'
         
     | 
| 
      
 43 
     | 
    
         
            +
                #   batman = Video.find_by_title 'Batman'
         
     | 
| 
      
 44 
     | 
    
         
            +
                #   toystory  = Video.find_by_title 'Toy Story'
         
     | 
| 
      
 45 
     | 
    
         
            +
                #
         
     | 
| 
      
 46 
     | 
    
         
            +
                #   batman.view request.remote_addr, bill
         
     | 
| 
      
 47 
     | 
    
         
            +
                #   toystory.view  request.remote_addr, bill
         
     | 
| 
      
 48 
     | 
    
         
            +
                #
         
     | 
| 
      
 49 
     | 
    
         
            +
                #   batman.view_count     # => 1
         
     | 
| 
      
 50 
     | 
    
         
            +
                #
         
     | 
| 
      
 51 
     | 
    
         
            +
                #
         
     | 
| 
      
 52 
     | 
    
         
            +
                module Viewed
         
     | 
| 
      
 53 
     | 
    
         
            +
                  class ViewedError < RuntimeError; end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  def self.included(base) #:nodoc:
         
     | 
| 
      
 56 
     | 
    
         
            +
                    base.extend(ClassMethods)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  module ClassMethods
         
     | 
| 
      
 60 
     | 
    
         
            +
                    # Make the model viewable.
         
     | 
| 
      
 61 
     | 
    
         
            +
                    # The Viewing model, holding the details of the viewings, will be created dynamically if it doesn't exist.
         
     | 
| 
      
 62 
     | 
    
         
            +
                    #
         
     | 
| 
      
 63 
     | 
    
         
            +
                    # * Adds a <tt>has_many :viewings</tt> association to the model for easy retrieval of the detailed viewings.
         
     | 
| 
      
 64 
     | 
    
         
            +
                    # * Adds a <tt>has_many :viewers</tt> association to the object.
         
     | 
| 
      
 65 
     | 
    
         
            +
                    # * Adds a <tt>has_many :viewings</tt> associations to the viewer class.
         
     | 
| 
      
 66 
     | 
    
         
            +
                    #
         
     | 
| 
      
 67 
     | 
    
         
            +
                    # === Options
         
     | 
| 
      
 68 
     | 
    
         
            +
                    # * <tt>:viewing_class</tt> -
         
     | 
| 
      
 69 
     | 
    
         
            +
                    #   class of the model used for the viewings. Defaults to Viewing. This class will be dynamically created if not already defined.
         
     | 
| 
      
 70 
     | 
    
         
            +
                    #   If the class is predefined, it must have in it the following definitions:
         
     | 
| 
      
 71 
     | 
    
         
            +
                    #   <tt>belongs_to :viewed, :polymorphic => true</tt>
         
     | 
| 
      
 72 
     | 
    
         
            +
                    #   <tt>belongs_to :viewer, :class_name => 'User', :foreign_key => :viewer_id</tt> replace user with the viewer class if needed.
         
     | 
| 
      
 73 
     | 
    
         
            +
                    # * <tt>:viewer_class</tt> -
         
     | 
| 
      
 74 
     | 
    
         
            +
                    #   class of the model that creates the viewing.
         
     | 
| 
      
 75 
     | 
    
         
            +
                    #   Defaults to User This class will NOT be created, so it must be defined in the app.
         
     | 
| 
      
 76 
     | 
    
         
            +
                    #   Use the IP address to prevent multiple viewings from the same client.
         
     | 
| 
      
 77 
     | 
    
         
            +
                    #
         
     | 
| 
      
 78 
     | 
    
         
            +
                    def rcrm_acts_as_viewed(options = {})
         
     | 
| 
      
 79 
     | 
    
         
            +
                      # don't allow multiple calls
         
     | 
| 
      
 80 
     | 
    
         
            +
                      return if self.included_modules.include?(ActsAsViewed::Viewed::ViewMethods)
         
     | 
| 
      
 81 
     | 
    
         
            +
                      send :include, ActsAsViewed::Viewed::ViewMethods
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                      # Create the model for ratings if it doesn't yet exist
         
     | 
| 
      
 84 
     | 
    
         
            +
                      viewing_class = options[:viewing_class] || 'Viewing'
         
     | 
| 
      
 85 
     | 
    
         
            +
                      viewer_class  = options[:viewer_class]  || 'User'
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                      unless Object.const_defined?(viewing_class)
         
     | 
| 
      
 88 
     | 
    
         
            +
                        Object.class_eval <<-EOV
         
     | 
| 
      
 89 
     | 
    
         
            +
                          class #{viewing_class} < ActiveRecord::Base
         
     | 
| 
      
 90 
     | 
    
         
            +
                            belongs_to :viewed, :polymorphic => true
         
     | 
| 
      
 91 
     | 
    
         
            +
                            belongs_to :viewer, :class_name => #{viewer_class}, :foreign_key => :viewer_id
         
     | 
| 
      
 92 
     | 
    
         
            +
                          end
         
     | 
| 
      
 93 
     | 
    
         
            +
                        EOV
         
     | 
| 
      
 94 
     | 
    
         
            +
                      end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                      # Rails < 3
         
     | 
| 
      
 97 
     | 
    
         
            +
                      # write_inheritable_attribute( :acts_as_viewed_options ,
         
     | 
| 
      
 98 
     | 
    
         
            +
                      #                                { :viewing_class => viewing_class,
         
     | 
| 
      
 99 
     | 
    
         
            +
                      #                                  :viewer_class => viewer_class } )
         
     | 
| 
      
 100 
     | 
    
         
            +
                      # class_inheritable_reader :acts_as_viewed_options
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                      # Rails >= 3
         
     | 
| 
      
 103 
     | 
    
         
            +
                      class_attribute :acts_as_viewed_options
         
     | 
| 
      
 104 
     | 
    
         
            +
                      self.acts_as_viewed_options = { :viewing_class => viewing_class,
         
     | 
| 
      
 105 
     | 
    
         
            +
                                                      :viewer_class => viewer_class }
         
     | 
| 
      
 106 
     | 
    
         
            +
                      class_eval do
         
     | 
| 
      
 107 
     | 
    
         
            +
                        has_many :viewings, :as => :viewed, :dependent => :delete_all, :class_name => viewing_class.to_s
         
     | 
| 
      
 108 
     | 
    
         
            +
                        has_many(:viewers, :through => :viewings, :class_name => viewer_class.to_s)
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                        before_create :init_viewing_fields
         
     | 
| 
      
 111 
     | 
    
         
            +
                      end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                      # Add to the User (or whatever the viewer is) a has_many viewings
         
     | 
| 
      
 114 
     | 
    
         
            +
                      viewer_as_class = viewer_class.constantize
         
     | 
| 
      
 115 
     | 
    
         
            +
                      return if viewer_as_class.instance_methods.include?('find_in_viewings')
         
     | 
| 
      
 116 
     | 
    
         
            +
                      viewer_as_class.class_eval <<-EOS
         
     | 
| 
      
 117 
     | 
    
         
            +
                        has_many :viewings, :foreign_key => :viewer_id, :class_name => #{viewing_class.to_s}
         
     | 
| 
      
 118 
     | 
    
         
            +
                      EOS
         
     | 
| 
      
 119 
     | 
    
         
            +
                    end
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                  module ViewMethods
         
     | 
| 
      
 123 
     | 
    
         
            +
                    def self.included(base) #:nodoc:
         
     | 
| 
      
 124 
     | 
    
         
            +
                      base.extend ClassMethods
         
     | 
| 
      
 125 
     | 
    
         
            +
                    end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                    # Is this object viewed already?
         
     | 
| 
      
 128 
     | 
    
         
            +
                    def viewed?
         
     | 
| 
      
 129 
     | 
    
         
            +
                      return (!self.views.nil? && self.views > 0) if attributes.has_key? 'views'
         
     | 
| 
      
 130 
     | 
    
         
            +
                      !viewings.first.nil?
         
     | 
| 
      
 131 
     | 
    
         
            +
                    end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                    # Get the number of viewings for this object based on the views field,
         
     | 
| 
      
 134 
     | 
    
         
            +
                    # or with a SQL query if the viewed objects doesn't have the views field
         
     | 
| 
      
 135 
     | 
    
         
            +
                    def view_count
         
     | 
| 
      
 136 
     | 
    
         
            +
                      return ("#{self.total_views}(#{self.views})" || 0) if attributes.has_key? 'views'
         
     | 
| 
      
 137 
     | 
    
         
            +
                      viewings.count
         
     | 
| 
      
 138 
     | 
    
         
            +
                    end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                    # Change views count (total_views and views) if it's existing in object
         
     | 
| 
      
 141 
     | 
    
         
            +
                    # If options[:only_total] == true count of unique views doesn't change
         
     | 
| 
      
 142 
     | 
    
         
            +
                    def increase_views_count(options)
         
     | 
| 
      
 143 
     | 
    
         
            +
                      if attributes.has_key?('views') && attributes.has_key?('total_views')
         
     | 
| 
      
 144 
     | 
    
         
            +
                        target = self
         
     | 
| 
      
 145 
     | 
    
         
            +
                        target.views = ((target.views || 0) + 1) unless options[:only_total]
         
     | 
| 
      
 146 
     | 
    
         
            +
                        target.total_views = ((target.total_views || 0) + 1)
         
     | 
| 
      
 147 
     | 
    
         
            +
                        target.record_timestamps = false
         
     | 
| 
      
 148 
     | 
    
         
            +
                        target.save(:validate => false, :touch => false)
         
     | 
| 
      
 149 
     | 
    
         
            +
                      end
         
     | 
| 
      
 150 
     | 
    
         
            +
                    end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                    # View the object with or without a viewer - create new or update as needed
         
     | 
| 
      
 153 
     | 
    
         
            +
                    #
         
     | 
| 
      
 154 
     | 
    
         
            +
                    # * <tt>ip</tt> - the viewer ip
         
     | 
| 
      
 155 
     | 
    
         
            +
                    # * <tt>viewer</tt> - an object of the viewer class. Must be valid and with an id to be used. Or nil
         
     | 
| 
      
 156 
     | 
    
         
            +
                    def view(ip, viewer = nil)
         
     | 
| 
      
 157 
     | 
    
         
            +
                      # Sanity checks for the parameters
         
     | 
| 
      
 158 
     | 
    
         
            +
                      viewing_class = acts_as_viewed_options[:viewing_class].constantize
         
     | 
| 
      
 159 
     | 
    
         
            +
                      if viewer && !(acts_as_viewed_options[:viewer_class].constantize === viewer)
         
     | 
| 
      
 160 
     | 
    
         
            +
                        raise ViewedError, "the viewer object must be the one used when defining acts_as_viewed (or a descendent of it). other objects are not acceptable"
         
     | 
| 
      
 161 
     | 
    
         
            +
                      end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                      viewing_class.transaction do
         
     | 
| 
      
 164 
     | 
    
         
            +
                        if !viewed_by? ip, viewer
         
     | 
| 
      
 165 
     | 
    
         
            +
                          view = viewing_class.new
         
     | 
| 
      
 166 
     | 
    
         
            +
                          view.viewer_id = viewer.id if viewer && !viewer.id.nil?
         
     | 
| 
      
 167 
     | 
    
         
            +
                          view.ip = ip
         
     | 
| 
      
 168 
     | 
    
         
            +
                          viewings << view
         
     | 
| 
      
 169 
     | 
    
         
            +
                          view.save
         
     | 
| 
      
 170 
     | 
    
         
            +
                          increase_views_count(:only_total => false)
         
     | 
| 
      
 171 
     | 
    
         
            +
                        else
         
     | 
| 
      
 172 
     | 
    
         
            +
                          increase_views_count(:only_total => true)
         
     | 
| 
      
 173 
     | 
    
         
            +
                        end
         
     | 
| 
      
 174 
     | 
    
         
            +
                        true
         
     | 
| 
      
 175 
     | 
    
         
            +
                      end
         
     | 
| 
      
 176 
     | 
    
         
            +
                    end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                    # Check if an item was already viewed by the given viewer
         
     | 
| 
      
 179 
     | 
    
         
            +
                    def viewed_by?(ip, viewer = nil)
         
     | 
| 
      
 180 
     | 
    
         
            +
                      if viewer && !viewer.nil? && !(acts_as_viewed_options[:viewer_class].constantize === viewer)
         
     | 
| 
      
 181 
     | 
    
         
            +
                        raise ViewedError, "the viewer object must be the one used when defining acts_as_viewed (or a descendent of it). other objects are not acceptable"
         
     | 
| 
      
 182 
     | 
    
         
            +
                      end
         
     | 
| 
      
 183 
     | 
    
         
            +
                      if viewer && !viewer.id.nil? && !viewer.anonymous?
         
     | 
| 
      
 184 
     | 
    
         
            +
                        return viewings.where("viewer_id = '#{viewer.id}'").any?
         
     | 
| 
      
 185 
     | 
    
         
            +
                      else
         
     | 
| 
      
 186 
     | 
    
         
            +
                        return viewings.where("ip = '#{ip}'").any?
         
     | 
| 
      
 187 
     | 
    
         
            +
                      end
         
     | 
| 
      
 188 
     | 
    
         
            +
                    end
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                    private
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                    def init_viewing_fields #:nodoc:
         
     | 
| 
      
 193 
     | 
    
         
            +
                      self.views ||= 0 if attributes.has_key?('views')
         
     | 
| 
      
 194 
     | 
    
         
            +
                    end
         
     | 
| 
      
 195 
     | 
    
         
            +
                  end
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                  module ClassMethods
         
     | 
| 
      
 198 
     | 
    
         
            +
                    # Generate the viewings columns on a table, to be used when creating the table
         
     | 
| 
      
 199 
     | 
    
         
            +
                    # in a migration. This is the preferred way to do in a migration that creates
         
     | 
| 
      
 200 
     | 
    
         
            +
                    # new tables as it will make it as part of the table creation, and not generate
         
     | 
| 
      
 201 
     | 
    
         
            +
                    # ALTER TABLE calls after the fact
         
     | 
| 
      
 202 
     | 
    
         
            +
                    def generate_viewings_columns(table)
         
     | 
| 
      
 203 
     | 
    
         
            +
                      table.column :views, :integer # uniq views
         
     | 
| 
      
 204 
     | 
    
         
            +
                      table.column :total_views, :integer
         
     | 
| 
      
 205 
     | 
    
         
            +
                    end
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                    # Create the needed columns for acts_as_viewed.
         
     | 
| 
      
 208 
     | 
    
         
            +
                    # To be used during migration, but can also be used in other places.
         
     | 
| 
      
 209 
     | 
    
         
            +
                    def add_viewings_columns
         
     | 
| 
      
 210 
     | 
    
         
            +
                      if !self.content_columns.find { |c| 'views' == c.name }
         
     | 
| 
      
 211 
     | 
    
         
            +
                        self.connection.add_column table_name, :views, :integer, :default => '0'
         
     | 
| 
      
 212 
     | 
    
         
            +
                        self.connection.add_column table_name, :total_views, :integer, :default => '0'
         
     | 
| 
      
 213 
     | 
    
         
            +
                        self.reset_column_information
         
     | 
| 
      
 214 
     | 
    
         
            +
                      end
         
     | 
| 
      
 215 
     | 
    
         
            +
                    end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                    # Remove the acts_as_viewed specific columns added with add_viewings_columns
         
     | 
| 
      
 218 
     | 
    
         
            +
                    # To be used during migration, but can also be used in other places
         
     | 
| 
      
 219 
     | 
    
         
            +
                    def remove_viewings_columns
         
     | 
| 
      
 220 
     | 
    
         
            +
                      if self.content_columns.find { |c| 'views' == c.name }
         
     | 
| 
      
 221 
     | 
    
         
            +
                        self.connection.remove_column table_name, :views
         
     | 
| 
      
 222 
     | 
    
         
            +
                        self.connection.remove_column table_name, :total_views
         
     | 
| 
      
 223 
     | 
    
         
            +
                        self.reset_column_information
         
     | 
| 
      
 224 
     | 
    
         
            +
                      end
         
     | 
| 
      
 225 
     | 
    
         
            +
                    end
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
                    # Create the viewings table
         
     | 
| 
      
 228 
     | 
    
         
            +
                    # === Options hash:
         
     | 
| 
      
 229 
     | 
    
         
            +
                    # * <tt>:table_name</tt> - use a table name other than viewings
         
     | 
| 
      
 230 
     | 
    
         
            +
                    # To be used during migration, but can also be used in other places
         
     | 
| 
      
 231 
     | 
    
         
            +
                    def create_viewings_table(options = {})
         
     | 
| 
      
 232 
     | 
    
         
            +
                      name = options[:table_name] || :viewings
         
     | 
| 
      
 233 
     | 
    
         
            +
                      if !self.connection.table_exists?(name)
         
     | 
| 
      
 234 
     | 
    
         
            +
                        self.connection.create_table(name) do |t|
         
     | 
| 
      
 235 
     | 
    
         
            +
                          t.column :viewer_id,   :integer
         
     | 
| 
      
 236 
     | 
    
         
            +
                          t.column :viewed_id,   :integer
         
     | 
| 
      
 237 
     | 
    
         
            +
                          t.column :viewed_type, :string
         
     | 
| 
      
 238 
     | 
    
         
            +
                          t.column :ip, :string, :limit => '24'
         
     | 
| 
      
 239 
     | 
    
         
            +
                          t.column :created_at, :datetime
         
     | 
| 
      
 240 
     | 
    
         
            +
                        end
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
                        self.connection.add_index(name, :viewer_id)
         
     | 
| 
      
 243 
     | 
    
         
            +
                        self.connection.add_index(name, [:viewed_type, :viewed_id])
         
     | 
| 
      
 244 
     | 
    
         
            +
                      end
         
     | 
| 
      
 245 
     | 
    
         
            +
                    end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
                    # Drop the viewings table.
         
     | 
| 
      
 248 
     | 
    
         
            +
                    # === Options hash:
         
     | 
| 
      
 249 
     | 
    
         
            +
                    # * <tt>:table_name</tt> - the name of the viewings table, defaults to viewings
         
     | 
| 
      
 250 
     | 
    
         
            +
                    # To be used during migration, but can also be used in other places
         
     | 
| 
      
 251 
     | 
    
         
            +
                    def drop_viewings_table(options = {})
         
     | 
| 
      
 252 
     | 
    
         
            +
                      name = options[:table_name] || :viewings
         
     | 
| 
      
 253 
     | 
    
         
            +
                      if self.connection.table_exists?(name)
         
     | 
| 
      
 254 
     | 
    
         
            +
                        self.connection.drop_table(name)
         
     | 
| 
      
 255 
     | 
    
         
            +
                      end
         
     | 
| 
      
 256 
     | 
    
         
            +
                    end
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
                    # Find all viewings for a specific viewer.
         
     | 
| 
      
 259 
     | 
    
         
            +
                    def find_viewed_by(viewer)
         
     | 
| 
      
 260 
     | 
    
         
            +
                      viewing_class = acts_as_viewed_options[:viewing_class].constantize
         
     | 
| 
      
 261 
     | 
    
         
            +
                      if !(acts_as_viewed_options[:viewer_class].constantize === viewer)
         
     | 
| 
      
 262 
     | 
    
         
            +
                        raise ViewedError, "The viewer object must be the one used when defining acts_as_viewed (or a descendent of it). other objects are not acceptable"
         
     | 
| 
      
 263 
     | 
    
         
            +
                      end
         
     | 
| 
      
 264 
     | 
    
         
            +
                      raise ViewedError, 'Viewer must be a valid and existing object' if viewer.nil? || viewer.id.nil?
         
     | 
| 
      
 265 
     | 
    
         
            +
                      raise ViewedError, 'Viewer must be a valid viewer' if !viewing_class.column_names.include?('viewer_id')
         
     | 
| 
      
 266 
     | 
    
         
            +
                      conds = ['viewed_type = ? AND viewer_id = ?', self.name, viewer.id]
         
     | 
| 
      
 267 
     | 
    
         
            +
                      acts_as_viewed_options[:viewing_class].constantize.where(conds).collect { |r| r.viewed_type.constantize.find_by_id r.viewed.id }
         
     | 
| 
      
 268 
     | 
    
         
            +
                    end
         
     | 
| 
      
 269 
     | 
    
         
            +
                  end
         
     | 
| 
      
 270 
     | 
    
         
            +
                end
         
     | 
| 
      
 271 
     | 
    
         
            +
              end
         
     | 
| 
      
 272 
     | 
    
         
            +
            end
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
            ActiveRecord::Base.send :include, YeshouaCrm::ActsAsViewed::Viewed
         
     | 
| 
         @@ -0,0 +1,80 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_record'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module YeshouaCrm
         
     | 
| 
      
 4 
     | 
    
         
            +
              module ActsAsVotable #:nodoc:
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Votable #:nodoc:
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def votable?
         
     | 
| 
      
 7 
     | 
    
         
            +
                    false
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def rcrm_acts_as_votable
         
     | 
| 
      
 11 
     | 
    
         
            +
                    require 'yeshoua_crm/acts_as_votable/votable'
         
     | 
| 
      
 12 
     | 
    
         
            +
                    include YeshouaCrm::ActsAsVotable::Votable
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    class_eval do
         
     | 
| 
      
 15 
     | 
    
         
            +
                      def self.votable?
         
     | 
| 
      
 16 
     | 
    
         
            +
                        true
         
     | 
| 
      
 17 
     | 
    
         
            +
                      end
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def create_index(table_name, column_name)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    return if self.connection.index_exists?(table_name, column_name)
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    self.connection.add_index table_name, column_name
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def create_votable_table(options = {})
         
     | 
| 
      
 28 
     | 
    
         
            +
                    votes_name_table = options[:votes] || :votes
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    if !self.connection.table_exists?(votes_name_table)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      self.connection.create_table(votes_name_table) do |t|
         
     | 
| 
      
 32 
     | 
    
         
            +
                        t.references :votable, :polymorphic => true
         
     | 
| 
      
 33 
     | 
    
         
            +
                        t.references :voter, :polymorphic => true
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                        t.column :vote_flag, :boolean
         
     | 
| 
      
 36 
     | 
    
         
            +
                        t.column :vote_scope, :string
         
     | 
| 
      
 37 
     | 
    
         
            +
                        t.column :vote_weight, :integer
         
     | 
| 
      
 38 
     | 
    
         
            +
                        t.column :vote_ip, :string
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                        t.timestamps
         
     | 
| 
      
 41 
     | 
    
         
            +
                      end
         
     | 
| 
      
 42 
     | 
    
         
            +
                    else #if table exists - check existence of separate columns
         
     | 
| 
      
 43 
     | 
    
         
            +
                      fields = {
         
     | 
| 
      
 44 
     | 
    
         
            +
                        :votable_id => :integer,
         
     | 
| 
      
 45 
     | 
    
         
            +
                        :votable_type => :string,
         
     | 
| 
      
 46 
     | 
    
         
            +
                        :voter_id => :integer,
         
     | 
| 
      
 47 
     | 
    
         
            +
                        :voter_type => :string,
         
     | 
| 
      
 48 
     | 
    
         
            +
                        :vote_flag => :boolean,
         
     | 
| 
      
 49 
     | 
    
         
            +
                        :vote_scope => :string,
         
     | 
| 
      
 50 
     | 
    
         
            +
                        :vote_weight => :integer,
         
     | 
| 
      
 51 
     | 
    
         
            +
                        :vote_ip => :string
         
     | 
| 
      
 52 
     | 
    
         
            +
                      }
         
     | 
| 
      
 53 
     | 
    
         
            +
                      fields.each do |name, type|
         
     | 
| 
      
 54 
     | 
    
         
            +
                        if !self.connection.column_exists?(votes_name_table, name)
         
     | 
| 
      
 55 
     | 
    
         
            +
                          self.connection.add_column(votes_name_table, name, type)
         
     | 
| 
      
 56 
     | 
    
         
            +
                        end
         
     | 
| 
      
 57 
     | 
    
         
            +
                      end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    if self.parent::VERSION::MAJOR < 4
         
     | 
| 
      
 62 
     | 
    
         
            +
                      create_index votes_name_table, [:votable_id, :votable_type, :vote_ip]
         
     | 
| 
      
 63 
     | 
    
         
            +
                      create_index votes_name_table, [:voter_id, :voter_type, :vote_ip]
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                    create_index votes_name_table, [:voter_id, :voter_type, :vote_scope]
         
     | 
| 
      
 67 
     | 
    
         
            +
                    create_index votes_name_table, [:votable_id, :votable_type, :vote_scope]
         
     | 
| 
      
 68 
     | 
    
         
            +
                    create_index votes_name_table, [:voter_type, :vote_scope, :vote_ip]
         
     | 
| 
      
 69 
     | 
    
         
            +
                    create_index votes_name_table, [:votable_type, :vote_scope, :vote_ip]
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  def drop_votable_table(options = {})
         
     | 
| 
      
 73 
     | 
    
         
            +
                    votes_name_table = options[:votes] || :votes
         
     | 
| 
      
 74 
     | 
    
         
            +
                    if self.connection.table_exists?(votes_name_table)
         
     | 
| 
      
 75 
     | 
    
         
            +
                      self.connection.drop_table votes_name_table
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module YeshouaCrm
         
     | 
| 
      
 2 
     | 
    
         
            +
              module ActsAsVotable
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Voter
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def voter?
         
     | 
| 
      
 5 
     | 
    
         
            +
                    false
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def rcrm_acts_as_voter(*args)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    require 'yeshoua_crm/acts_as_votable/voter'
         
     | 
| 
      
 10 
     | 
    
         
            +
                    include YeshouaCrm::ActsAsVotable::Voter
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    class_eval do
         
     | 
| 
      
 13 
     | 
    
         
            +
                      def self.voter?
         
     | 
| 
      
 14 
     | 
    
         
            +
                        true
         
     | 
| 
      
 15 
     | 
    
         
            +
                      end
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,323 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'yeshoua_crm/helpers/vote_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module YeshouaCrm
         
     | 
| 
      
 4 
     | 
    
         
            +
              module ActsAsVotable
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Votable
         
     | 
| 
      
 6 
     | 
    
         
            +
                  include ActsAsVotable::Helpers::Words
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def self.included(base)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    # allow the user to define these himself
         
     | 
| 
      
 10 
     | 
    
         
            +
                    aliases = {
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                      :vote_up => [
         
     | 
| 
      
 13 
     | 
    
         
            +
                        :up_by, :upvote_by, :like_by, :liked_by,
         
     | 
| 
      
 14 
     | 
    
         
            +
                        :up_from, :upvote_from, :upvote_by, :like_from, :liked_from, :vote_from
         
     | 
| 
      
 15 
     | 
    
         
            +
                      ],
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                      :vote_down => [
         
     | 
| 
      
 18 
     | 
    
         
            +
                        :down_by, :downvote_by, :dislike_by, :disliked_by,
         
     | 
| 
      
 19 
     | 
    
         
            +
                        :down_from, :downvote_from, :downvote_by, :dislike_by, :disliked_by
         
     | 
| 
      
 20 
     | 
    
         
            +
                      ],
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                      :get_up_votes => [
         
     | 
| 
      
 23 
     | 
    
         
            +
                        :get_true_votes, :get_ups, :get_upvotes, :get_likes, :get_positives, :get_for_votes,
         
     | 
| 
      
 24 
     | 
    
         
            +
                      ],
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                      :get_down_votes => [
         
     | 
| 
      
 27 
     | 
    
         
            +
                        :get_false_votes, :get_downs, :get_downvotes, :get_dislikes, :get_negatives
         
     | 
| 
      
 28 
     | 
    
         
            +
                      ],
         
     | 
| 
      
 29 
     | 
    
         
            +
                      :unvote_by => [
         
     | 
| 
      
 30 
     | 
    
         
            +
                        :unvote_up, :unvote_down, :unliked_by, :undisliked_by
         
     | 
| 
      
 31 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 32 
     | 
    
         
            +
                    }
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    base.class_eval do
         
     | 
| 
      
 35 
     | 
    
         
            +
                      has_many :votes_for, :class_name => 'YeshouaCrm::ActsAsVotable::Vote', :as => :votable, :dependent => :destroy do
         
     | 
| 
      
 36 
     | 
    
         
            +
                        def voters
         
     | 
| 
      
 37 
     | 
    
         
            +
                          includes(:voter).map(&:voter)
         
     | 
| 
      
 38 
     | 
    
         
            +
                        end
         
     | 
| 
      
 39 
     | 
    
         
            +
                      end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                      aliases.each do |method, links|
         
     | 
| 
      
 42 
     | 
    
         
            +
                        links.each do |new_method|
         
     | 
| 
      
 43 
     | 
    
         
            +
                          alias_method(new_method, method)
         
     | 
| 
      
 44 
     | 
    
         
            +
                        end
         
     | 
| 
      
 45 
     | 
    
         
            +
                      end
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  attr_accessor :vote_registered
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  def vote_registered?
         
     | 
| 
      
 52 
     | 
    
         
            +
                    self.vote_registered
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  def default_conditions
         
     | 
| 
      
 56 
     | 
    
         
            +
                    {
         
     | 
| 
      
 57 
     | 
    
         
            +
                      :votable_id => self.id,
         
     | 
| 
      
 58 
     | 
    
         
            +
                      :votable_type => self.class.base_class.name.to_s
         
     | 
| 
      
 59 
     | 
    
         
            +
                    }
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  # voting
         
     | 
| 
      
 63 
     | 
    
         
            +
                  def vote_by(args = {})
         
     | 
| 
      
 64 
     | 
    
         
            +
                    options = {
         
     | 
| 
      
 65 
     | 
    
         
            +
                      :vote => true,
         
     | 
| 
      
 66 
     | 
    
         
            +
                      :vote_scope => nil
         
     | 
| 
      
 67 
     | 
    
         
            +
                    }.merge(args)
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                    self.vote_registered = false
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    return false if options[:voter].nil?
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    # find the vote
         
     | 
| 
      
 74 
     | 
    
         
            +
                    vote_conditions = { :vote_scope => options[:vote_scope], :voter_type => options[:voter].class.base_class.name }
         
     | 
| 
      
 75 
     | 
    
         
            +
                    vote_conditions.merge!(options[:vote_by_ip] ? { :vote_ip => options[:vote_ip] } : { :voter_id => options[:voter].id} )
         
     | 
| 
      
 76 
     | 
    
         
            +
                    votes_for = find_votes_for(vote_conditions)
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    if votes_for.count == 0 || options[:duplicate]
         
     | 
| 
      
 79 
     | 
    
         
            +
                      # this voter has never voted
         
     | 
| 
      
 80 
     | 
    
         
            +
                      vote_params = { :votable => self, :voter => options[:voter], :vote_scope => options[:vote_scope] }
         
     | 
| 
      
 81 
     | 
    
         
            +
                      vote_params[:vote_ip] = options[:vote_ip] if options[:vote_ip]
         
     | 
| 
      
 82 
     | 
    
         
            +
                      vote = YeshouaCrm::ActsAsVotable::Vote.new(vote_params)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    else
         
     | 
| 
      
 84 
     | 
    
         
            +
                      # this voter is potentially changing his vote
         
     | 
| 
      
 85 
     | 
    
         
            +
                      vote = votes_for.last
         
     | 
| 
      
 86 
     | 
    
         
            +
                    end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                    vote.vote_flag = votable_words.meaning_of(options[:vote])
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                    # Allowing for a vote_weight to be associated with every vote. Could change with every voter object
         
     | 
| 
      
 91 
     | 
    
         
            +
                    vote.vote_weight = (options[:vote_weight].to_i if options[:vote_weight].present?) || 1
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                    return false if vote.invalid?
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                    self.vote_registered = vote.changed?
         
     | 
| 
      
 96 
     | 
    
         
            +
                    vote.save!(validate: false)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    update_cached_votes(options[:vote_scope])
         
     | 
| 
      
 98 
     | 
    
         
            +
                    vote
         
     | 
| 
      
 99 
     | 
    
         
            +
                  end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                  def unvote(args = {})
         
     | 
| 
      
 102 
     | 
    
         
            +
                    return false if (!args[:vote_by_ip] && args[:voter].nil?) || (args[:vote_by_ip] && args[:vote_ip].nil?)
         
     | 
| 
      
 103 
     | 
    
         
            +
                    vote_conditions = { :vote_scope => args[:vote_scope], :voter_type => args[:voter].class.base_class.name }
         
     | 
| 
      
 104 
     | 
    
         
            +
                    vote_conditions.merge!(args[:vote_by_ip] ? { :vote_ip => args[:vote_ip] } : { :voter_id => args[:voter].id})
         
     | 
| 
      
 105 
     | 
    
         
            +
                    votes_for = find_votes_for(vote_conditions)
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                    return true if votes_for.empty?
         
     | 
| 
      
 108 
     | 
    
         
            +
                    votes_for.each(&:destroy)
         
     | 
| 
      
 109 
     | 
    
         
            +
                    update_cached_votes args[:vote_scope]
         
     | 
| 
      
 110 
     | 
    
         
            +
                    self.vote_registered = false if votes_for.count == 0
         
     | 
| 
      
 111 
     | 
    
         
            +
                    true
         
     | 
| 
      
 112 
     | 
    
         
            +
                  end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                  def vote_up(voter, options={})
         
     | 
| 
      
 115 
     | 
    
         
            +
                    self.vote_by :voter => voter, :vote => true,
         
     | 
| 
      
 116 
     | 
    
         
            +
                                 :vote_scope => options[:vote_scope], :vote_weight => options[:vote_weight], :vote_ip => options[:vote_ip],
         
     | 
| 
      
 117 
     | 
    
         
            +
                                 :vote_by_ip => options[:vote_by_ip]
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                  def vote_down(voter, options={})
         
     | 
| 
      
 121 
     | 
    
         
            +
                    self.vote_by :voter => voter, :vote => false,
         
     | 
| 
      
 122 
     | 
    
         
            +
                                 :vote_scope => options[:vote_scope], :vote_weight => options[:vote_weight], :vote_ip => options[:vote_ip],
         
     | 
| 
      
 123 
     | 
    
         
            +
                                 :vote_by_ip => options[:vote_by_ip]
         
     | 
| 
      
 124 
     | 
    
         
            +
                  end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                  def unvote_by(voter, options = {})
         
     | 
| 
      
 127 
     | 
    
         
            +
                    # Does not need vote_weight since the votes_for are anyway getting destroyed
         
     | 
| 
      
 128 
     | 
    
         
            +
                    self.unvote :voter => voter, :vote_scope => options[:vote_scope], :vote_ip => options[:vote_ip],
         
     | 
| 
      
 129 
     | 
    
         
            +
                                :vote_by_ip => options[:vote_by_ip]
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  def scope_cache_field(field, vote_scope)
         
     | 
| 
      
 133 
     | 
    
         
            +
                    return field if vote_scope.nil?
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                    case field
         
     | 
| 
      
 136 
     | 
    
         
            +
                    when :cached_votes_total=
         
     | 
| 
      
 137 
     | 
    
         
            +
                      "cached_scoped_#{vote_scope}_votes_total="
         
     | 
| 
      
 138 
     | 
    
         
            +
                    when :cached_votes_total
         
     | 
| 
      
 139 
     | 
    
         
            +
                      "cached_scoped_#{vote_scope}_votes_total"
         
     | 
| 
      
 140 
     | 
    
         
            +
                    when :cached_votes_up=
         
     | 
| 
      
 141 
     | 
    
         
            +
                      "cached_scoped_#{vote_scope}_votes_up="
         
     | 
| 
      
 142 
     | 
    
         
            +
                    when :cached_votes_up
         
     | 
| 
      
 143 
     | 
    
         
            +
                      "cached_scoped_#{vote_scope}_votes_up"
         
     | 
| 
      
 144 
     | 
    
         
            +
                    when :cached_votes_down=
         
     | 
| 
      
 145 
     | 
    
         
            +
                      "cached_scoped_#{vote_scope}_votes_down="
         
     | 
| 
      
 146 
     | 
    
         
            +
                    when :cached_votes_down
         
     | 
| 
      
 147 
     | 
    
         
            +
                      "cached_scoped_#{vote_scope}_votes_down"
         
     | 
| 
      
 148 
     | 
    
         
            +
                    when :cached_votes_score=
         
     | 
| 
      
 149 
     | 
    
         
            +
                      "cached_scoped_#{vote_scope}_votes_score="
         
     | 
| 
      
 150 
     | 
    
         
            +
                    when :cached_votes_score
         
     | 
| 
      
 151 
     | 
    
         
            +
                      "cached_scoped_#{vote_scope}_votes_score"
         
     | 
| 
      
 152 
     | 
    
         
            +
                    when :cached_weighted_total
         
     | 
| 
      
 153 
     | 
    
         
            +
                      "cached_weighted_#{vote_scope}_total"
         
     | 
| 
      
 154 
     | 
    
         
            +
                    when :cached_weighted_total=
         
     | 
| 
      
 155 
     | 
    
         
            +
                      "cached_weighted_#{vote_scope}_total="
         
     | 
| 
      
 156 
     | 
    
         
            +
                    when :cached_weighted_score
         
     | 
| 
      
 157 
     | 
    
         
            +
                      "cached_weighted_#{vote_scope}_score"
         
     | 
| 
      
 158 
     | 
    
         
            +
                    when :cached_weighted_score=
         
     | 
| 
      
 159 
     | 
    
         
            +
                      "cached_weighted_#{vote_scope}_score="
         
     | 
| 
      
 160 
     | 
    
         
            +
                    when :cached_weighted_average
         
     | 
| 
      
 161 
     | 
    
         
            +
                      "cached_weighted_#{vote_scope}_average"
         
     | 
| 
      
 162 
     | 
    
         
            +
                    when :cached_weighted_average=
         
     | 
| 
      
 163 
     | 
    
         
            +
                      "cached_weighted_#{vote_scope}_average="
         
     | 
| 
      
 164 
     | 
    
         
            +
                    end
         
     | 
| 
      
 165 
     | 
    
         
            +
                  end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                  # caching
         
     | 
| 
      
 168 
     | 
    
         
            +
                  def update_cached_votes(vote_scope = nil)
         
     | 
| 
      
 169 
     | 
    
         
            +
                    updates = {}
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                    if self.respond_to?(:cached_votes_total=)
         
     | 
| 
      
 172 
     | 
    
         
            +
                      updates[:cached_votes_total] = count_votes_total(true)
         
     | 
| 
      
 173 
     | 
    
         
            +
                    end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                    if self.respond_to?(:cached_votes_up=)
         
     | 
| 
      
 176 
     | 
    
         
            +
                      updates[:cached_votes_up] = count_votes_up(true)
         
     | 
| 
      
 177 
     | 
    
         
            +
                    end
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                    if self.respond_to?(:cached_votes_down=)
         
     | 
| 
      
 180 
     | 
    
         
            +
                      updates[:cached_votes_down] = count_votes_down(true)
         
     | 
| 
      
 181 
     | 
    
         
            +
                    end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                    if self.respond_to?(:cached_votes_score=)
         
     | 
| 
      
 184 
     | 
    
         
            +
                      updates[:cached_votes_score] = (
         
     | 
| 
      
 185 
     | 
    
         
            +
                        (updates[:cached_votes_up] || count_votes_up(true)) -
         
     | 
| 
      
 186 
     | 
    
         
            +
                        (updates[:cached_votes_down] || count_votes_down(true))
         
     | 
| 
      
 187 
     | 
    
         
            +
                      )
         
     | 
| 
      
 188 
     | 
    
         
            +
                    end
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                    if self.respond_to?(:cached_weighted_total=)
         
     | 
| 
      
 191 
     | 
    
         
            +
                      updates[:cached_weighted_total] = weighted_total(true)
         
     | 
| 
      
 192 
     | 
    
         
            +
                    end
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                    if self.respond_to?(:cached_weighted_score=)
         
     | 
| 
      
 195 
     | 
    
         
            +
                      updates[:cached_weighted_score] = weighted_score(true)
         
     | 
| 
      
 196 
     | 
    
         
            +
                    end
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                    if self.respond_to?(:cached_weighted_average=)
         
     | 
| 
      
 199 
     | 
    
         
            +
                      updates[:cached_weighted_average] = weighted_average(true)
         
     | 
| 
      
 200 
     | 
    
         
            +
                    end
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                    if vote_scope
         
     | 
| 
      
 203 
     | 
    
         
            +
                      if self.respond_to?(scope_cache_field :cached_votes_total=, vote_scope)
         
     | 
| 
      
 204 
     | 
    
         
            +
                        updates[scope_cache_field :cached_votes_total, vote_scope] = count_votes_total(true, vote_scope)
         
     | 
| 
      
 205 
     | 
    
         
            +
                      end
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                      if self.respond_to?(scope_cache_field :cached_votes_up=, vote_scope)
         
     | 
| 
      
 208 
     | 
    
         
            +
                        updates[scope_cache_field :cached_votes_up, vote_scope] = count_votes_up(true, vote_scope)
         
     | 
| 
      
 209 
     | 
    
         
            +
                      end
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                      if self.respond_to?(scope_cache_field :cached_votes_down=, vote_scope)
         
     | 
| 
      
 212 
     | 
    
         
            +
                        updates[scope_cache_field :cached_votes_down, vote_scope] = count_votes_down(true, vote_scope)
         
     | 
| 
      
 213 
     | 
    
         
            +
                      end
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
      
 215 
     | 
    
         
            +
                      if self.respond_to?(scope_cache_field :cached_weighted_total=, vote_scope)
         
     | 
| 
      
 216 
     | 
    
         
            +
                        updates[scope_cache_field :cached_weighted_total, vote_scope] = weighted_total(true, vote_scope)
         
     | 
| 
      
 217 
     | 
    
         
            +
                      end
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
                      if self.respond_to?(scope_cache_field :cached_weighted_score=, vote_scope)
         
     | 
| 
      
 220 
     | 
    
         
            +
                        updates[scope_cache_field :cached_weighted_score, vote_scope] = weighted_score(true, vote_scope)
         
     | 
| 
      
 221 
     | 
    
         
            +
                      end
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
                      if self.respond_to?(scope_cache_field :cached_votes_score=, vote_scope)
         
     | 
| 
      
 224 
     | 
    
         
            +
                        updates[scope_cache_field :cached_votes_score, vote_scope] = (
         
     | 
| 
      
 225 
     | 
    
         
            +
                          (updates[scope_cache_field :cached_votes_up, vote_scope] || count_votes_up(true, vote_scope)) -
         
     | 
| 
      
 226 
     | 
    
         
            +
                          (updates[scope_cache_field :cached_votes_down, vote_scope] || count_votes_down(true, vote_scope))
         
     | 
| 
      
 227 
     | 
    
         
            +
                        )
         
     | 
| 
      
 228 
     | 
    
         
            +
                      end
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                      if self.respond_to?(scope_cache_field :cached_weighted_average=, vote_scope)
         
     | 
| 
      
 231 
     | 
    
         
            +
                        updates[scope_cache_field :cached_weighted_average, vote_scope] = weighted_average(true, vote_scope)
         
     | 
| 
      
 232 
     | 
    
         
            +
                      end
         
     | 
| 
      
 233 
     | 
    
         
            +
                    end
         
     | 
| 
      
 234 
     | 
    
         
            +
                    self.record_timestamps = false
         
     | 
| 
      
 235 
     | 
    
         
            +
                    if (::ActiveRecord::VERSION::MAJOR == 3) && (::ActiveRecord::VERSION::MINOR != 0)
         
     | 
| 
      
 236 
     | 
    
         
            +
                      self.update_attributes(updates, :without_protection => true) if !updates.empty?
         
     | 
| 
      
 237 
     | 
    
         
            +
                    else
         
     | 
| 
      
 238 
     | 
    
         
            +
                      self.update_attributes(updates) if !updates.empty?
         
     | 
| 
      
 239 
     | 
    
         
            +
                    end
         
     | 
| 
      
 240 
     | 
    
         
            +
                  end
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
                  # results
         
     | 
| 
      
 243 
     | 
    
         
            +
                  def find_votes_for(extra_conditions = {})
         
     | 
| 
      
 244 
     | 
    
         
            +
                    votes_for.where(extra_conditions)
         
     | 
| 
      
 245 
     | 
    
         
            +
                  end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
                  def get_up_votes(options = {})
         
     | 
| 
      
 248 
     | 
    
         
            +
                    vote_scope_hash = scope_or_empty_hash(options[:vote_scope])
         
     | 
| 
      
 249 
     | 
    
         
            +
                    find_votes_for({:vote_flag => true}.merge(vote_scope_hash))
         
     | 
| 
      
 250 
     | 
    
         
            +
                  end
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
      
 252 
     | 
    
         
            +
                  def get_down_votes(options = {})
         
     | 
| 
      
 253 
     | 
    
         
            +
                    vote_scope_hash = scope_or_empty_hash(options[:vote_scope])
         
     | 
| 
      
 254 
     | 
    
         
            +
                    find_votes_for({ :vote_flag => false }.merge(vote_scope_hash))
         
     | 
| 
      
 255 
     | 
    
         
            +
                  end
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
                  # counting
         
     | 
| 
      
 258 
     | 
    
         
            +
                  def count_votes_total(skip_cache = false, vote_scope = nil)
         
     | 
| 
      
 259 
     | 
    
         
            +
                    if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_total, vote_scope)
         
     | 
| 
      
 260 
     | 
    
         
            +
                      return self.send(scope_cache_field :cached_votes_total, vote_scope)
         
     | 
| 
      
 261 
     | 
    
         
            +
                    end
         
     | 
| 
      
 262 
     | 
    
         
            +
                    find_votes_for(scope_or_empty_hash(vote_scope)).count
         
     | 
| 
      
 263 
     | 
    
         
            +
                  end
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
                  def count_votes_up(skip_cache = false, vote_scope = nil)
         
     | 
| 
      
 266 
     | 
    
         
            +
                    if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_up, vote_scope)
         
     | 
| 
      
 267 
     | 
    
         
            +
                      return self.send(scope_cache_field :cached_votes_up, vote_scope)
         
     | 
| 
      
 268 
     | 
    
         
            +
                    end
         
     | 
| 
      
 269 
     | 
    
         
            +
                    get_up_votes(:vote_scope => vote_scope).count
         
     | 
| 
      
 270 
     | 
    
         
            +
                  end
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                  def count_votes_down(skip_cache = false, vote_scope = nil)
         
     | 
| 
      
 273 
     | 
    
         
            +
                    if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_down, vote_scope)
         
     | 
| 
      
 274 
     | 
    
         
            +
                      return self.send(scope_cache_field :cached_votes_down, vote_scope)
         
     | 
| 
      
 275 
     | 
    
         
            +
                    end
         
     | 
| 
      
 276 
     | 
    
         
            +
                    get_down_votes(:vote_scope => vote_scope).count
         
     | 
| 
      
 277 
     | 
    
         
            +
                  end
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
                  def weighted_total(skip_cache = false, vote_scope = nil)
         
     | 
| 
      
 280 
     | 
    
         
            +
                    if !skip_cache && self.respond_to?(scope_cache_field :cached_weighted_total, vote_scope)
         
     | 
| 
      
 281 
     | 
    
         
            +
                      return self.send(scope_cache_field :cached_weighted_total, vote_scope)
         
     | 
| 
      
 282 
     | 
    
         
            +
                    end
         
     | 
| 
      
 283 
     | 
    
         
            +
                    ups = get_up_votes(:vote_scope => vote_scope).sum(:vote_weight)
         
     | 
| 
      
 284 
     | 
    
         
            +
                    downs = get_down_votes(:vote_scope => vote_scope).sum(:vote_weight)
         
     | 
| 
      
 285 
     | 
    
         
            +
                    ups + downs
         
     | 
| 
      
 286 
     | 
    
         
            +
                  end
         
     | 
| 
      
 287 
     | 
    
         
            +
             
     | 
| 
      
 288 
     | 
    
         
            +
                  def weighted_score(skip_cache = false, vote_scope = nil)
         
     | 
| 
      
 289 
     | 
    
         
            +
                    if !skip_cache && self.respond_to?(scope_cache_field :cached_weighted_score, vote_scope)
         
     | 
| 
      
 290 
     | 
    
         
            +
                      return self.send(scope_cache_field :cached_weighted_score, vote_scope)
         
     | 
| 
      
 291 
     | 
    
         
            +
                    end
         
     | 
| 
      
 292 
     | 
    
         
            +
                    ups = get_up_votes(:vote_scope => vote_scope).sum(:vote_weight)
         
     | 
| 
      
 293 
     | 
    
         
            +
                    downs = get_down_votes(:vote_scope => vote_scope).sum(:vote_weight)
         
     | 
| 
      
 294 
     | 
    
         
            +
                    ups - downs
         
     | 
| 
      
 295 
     | 
    
         
            +
                  end
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
                  def weighted_average(skip_cache = false, vote_scope = nil)
         
     | 
| 
      
 298 
     | 
    
         
            +
                    if !skip_cache && self.respond_to?(scope_cache_field :cached_weighted_average, vote_scope)
         
     | 
| 
      
 299 
     | 
    
         
            +
                      return self.send(scope_cache_field :cached_weighted_average, vote_scope)
         
     | 
| 
      
 300 
     | 
    
         
            +
                    end
         
     | 
| 
      
 301 
     | 
    
         
            +
             
     | 
| 
      
 302 
     | 
    
         
            +
                    count = count_votes_total(skip_cache, vote_scope).to_i
         
     | 
| 
      
 303 
     | 
    
         
            +
                    if count > 0
         
     | 
| 
      
 304 
     | 
    
         
            +
                      weighted_score(skip_cache, vote_scope).to_f / count
         
     | 
| 
      
 305 
     | 
    
         
            +
                    else
         
     | 
| 
      
 306 
     | 
    
         
            +
                      0.0
         
     | 
| 
      
 307 
     | 
    
         
            +
                    end
         
     | 
| 
      
 308 
     | 
    
         
            +
                  end
         
     | 
| 
      
 309 
     | 
    
         
            +
             
     | 
| 
      
 310 
     | 
    
         
            +
                  # voters
         
     | 
| 
      
 311 
     | 
    
         
            +
                  def voted_on_by?(voter)
         
     | 
| 
      
 312 
     | 
    
         
            +
                    votes = find_votes_for :voter_id => voter.id, :voter_type => voter.class.base_class.name
         
     | 
| 
      
 313 
     | 
    
         
            +
                    votes.count > 0
         
     | 
| 
      
 314 
     | 
    
         
            +
                  end
         
     | 
| 
      
 315 
     | 
    
         
            +
             
     | 
| 
      
 316 
     | 
    
         
            +
                  private
         
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
                  def scope_or_empty_hash(vote_scope)
         
     | 
| 
      
 319 
     | 
    
         
            +
                    vote_scope ? { :vote_scope => vote_scope } : {}
         
     | 
| 
      
 320 
     | 
    
         
            +
                  end
         
     | 
| 
      
 321 
     | 
    
         
            +
                end
         
     | 
| 
      
 322 
     | 
    
         
            +
              end
         
     | 
| 
      
 323 
     | 
    
         
            +
            end
         
     |