module ActsAsFavoritor #:nodoc: module Favoritor def self.included base base.extend ClassMethods end module ClassMethods def acts_as_favoritor has_many :favorites, as: :favoritor, dependent: :destroy include ActsAsFavoritor::Favoritor::InstanceMethods include ActsAsFavoritor::FavoritorLib end end module InstanceMethods # Returns true if this instance has favorited the object passed as an argument. def favorited? favoritable, options = {} if options.has_key?(:multiple_scopes) == false options[:parameter] = favoritable validate_scopes __method__, options elsif options[:multiple_scopes] == true results = {} options[:scope].each do |scope| results[scope] = 0 < Favorite.unblocked.send(scope + '_list').for_favoritor(self).for_favoritable(favoritable).count end return results else return 0 < Favorite.unblocked.send(options[:scope] + '_list').for_favoritor(self).for_favoritable(favoritable).count end end # Returns the number of objects this instance has favorited. def favorites_count options = {} if options.has_key?(:multiple_scopes) == false validate_scopes __method__, options elsif options[:multiple_scopes] == true raise options.to_s results = {} options[:scope].each do |scope| results[scope] = Favorite.unblocked.send(scope + '_list').for_favoritor(self).count end return results else return Favorite.unblocked.send(options[:scope] + '_list').for_favoritor(self).count end end # Creates a new favorite record for this instance to favorite the passed object. # Does not allow duplicate records to be created. def favorite favoritable, options = {} if options.has_key?(:multiple_scopes) == false options[:parameter] = favoritable validate_scopes __method__, options elsif options[:multiple_scopes] == true results = {} options[:scope].each do |scope| if self != favoritable && scope != 'all' params = {favoritable_id: favoritable.id, favoritable_type: parent_class_name(favoritable), scope: scope} results[scope] = favorites.where(params).first_or_create! end end return results else if self != favoritable && options[:scope] != 'all' params = {favoritable_id: favoritable.id, favoritable_type: parent_class_name(favoritable), scope: options[:scope]} return favorites.where(params).first_or_create! end end end # Deletes the favorite record if it exists. def remove_favorite favoritable, options = {} if options.has_key?(:multiple_scopes) == false options[:parameter] = favoritable validate_scopes __method__, options elsif options[:multiple_scopes] == true results = {} options[:scope].each do |scope| if favorite = get_favorite(favoritable).send(scope + '_list') results[scope] = favorite.destroy end end return results else if favorite = get_favorite(favoritable).send(options[:scope] + '_list') return favorite.destroy end end end # returns the favorite records to the current instance def favorites_scoped options = {} if options.has_key?(:multiple_scopes) == false validate_scopes __method__, options elsif options[:multiple_scopes] == true results = {} options[:scope].each do |scope| results[scope] = favorites.unblocked.send(scope + '_list').includes :favoritable end return results else return favorites.unblocked.send(options[:scope] + '_list').includes :favoritable end end # Returns the favorite records related to this instance by type. def favorites_by_type favoritable_type, options = {} if options.has_key?(:multiple_scopes) == false options[:parameter] = favoritable_type validate_scopes __method__, options elsif options[:multiple_scopes] == true results = {} options[:scope].each do |scope| favorites_scope = favorites_scoped(scope).for_favoritable_type favoritable_type results[scope] = favorites_scope = apply_options_to_scope favorites_scope, options end return results else favorites_scope = favorites_scoped(options[:scope]).for_favoritable_type favoritable_type return favorites_scope = apply_options_to_scope(favorites_scope, options) end end # Returns the favorite records related to this instance with the favoritable included. def all_favorites options = {} if options.has_key?(:multiple_scopes) == false validate_scopes __method__, options elsif options[:multiple_scopes] == true results = {} options[:scope].each do |scope| favorites_scope = favorites_scoped scope results[scope] = favorites_scope = apply_options_to_scope favorites_scope, options end return results else favorites_scope = favorites_scoped options[:scope] return favorites_scope = apply_options_to_scope(favorites_scope, options) end end # Returns the actual records which this instance has favorited. def all_favorited options = {} return all_favorites(options).collect{ |f| f.favoritable } end # Returns the actual records of a particular type which this record has fovarited. def favorited_by_type favoritable_type, options = {} if options.has_key?(:multiple_scopes) == false options[:parameter] = favoritable_type validate_scopes __method__, options elsif options[:multiple_scopes] == true results = {} options[:scope].each do |scope| favoritables = favoritable_type.constantize.joins(:favorited).where('favorites.blocked': false, 'favorites.favoritor_id': id, 'favorites.favoritor_type': parent_class_name(self), 'favorites.favoritable_type': favoritable_type, 'favorites.scope': scope) if options.has_key? :limit favoritables = favoritables.limit options[:limit] end if options.has_key? :includes favoritables = favoritables.includes options[:includes] end results[scope] = favoritables end return results else favoritables = favoritable_type.constantize.joins(:favorited).where('favorites.blocked': false, 'favorites.favoritor_id': id, 'favorites.favoritor_type': parent_class_name(self), 'favorites.favoritable_type': favoritable_type, 'favorites.scope': options[:scope]) if options.has_key? :limit favoritables = favoritables.limit options[:limit] end if options.has_key? :includes favoritables = favoritables.includes options[:includes] end return favoritables end end def favorited_by_type_count favoritable_type, options = {} if options.has_key?(:multiple_scopes) == false options[:parameter] = favoritable_type validate_scopes __method__, options elsif options[:multiple_scopes] == true results = {} options[:scope].each do |scope| results[scope] = favorites.unblocked.send(scope + '_list').for_favoritable_type(favoritable_type).count end return results else return favorites.unblocked.send(options[:scope] + '_list').for_favoritable_type(favoritable_type).count end end # Allows magic names on favorited_by_type # e.g. favorited_users == favorited_by_type 'User' # Allows magic names on favorited_by_type_count # e.g. favorited_users_count == favorited_by_type_count 'User' def method_missing m, *args if m.to_s[/favorited_(.+)_count/] favorited_by_type_count $1.singularize.classify elsif m.to_s[/favorited_(.+)/] favorited_by_type $1.singularize.classify else super end end def respond_to? m, include_private = false super || m.to_s[/favorited_(.+)_count/] || m.to_s[/favorited_(.+)/] end # Returns a favorite record for the current instance and favoritable object. def get_favorite favoritable, options = {} if options.has_key?(:multiple_scopes) == false options[:parameter] = favoritable validate_scopes __method__, options elsif options[:multiple_scopes] == true results = {} options[:scope].each do |scope| results[scope] = favorites.unblocked.send(scope + '_list').for_favoritable(favoritable).first end return results else return favorites.unblocked.send(options[:scope] + '_list').for_favoritable(favoritable).first end end end end end