module SemanticallyTaggable::Taggable::Collection::ClassMethods

Public Instance Methods

all_tag_counts(options = {}) click to toggle source

Calculate the tag counts for all tags.

@param [Hash] options Options:

* :start_at   - Restrict the tags to those created after a certain time
* :end_at     - Restrict the tags to those created before a certain time
* :conditions - A piece of SQL conditions to add to the query
* :limit      - The maximum number of tags to return
* :order      - A piece of SQL to order by. Eg 'tags.count desc' or 'taggings.created_at desc'
* :at_least   - Exclude tags with a frequency less than the given value
* :at_most    - Exclude tags with a frequency greater than the given value
* :on         - Scope the find to only include a certain scheme name
# File lib/semantically_taggable/semantically_taggable/collection.rb, line 53
def all_tag_counts(options = {})
  options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :on, :id

  scope = {}

  ## Generate conditions:
  options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]     
  scheme_name = options.delete(:on)

  start_at_conditions = sanitize_sql(["#{SemanticallyTaggable::Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
  end_at_conditions   = sanitize_sql(["#{SemanticallyTaggable::Tagging.table_name}.created_at <= ?", options.delete(:end_at)])   if options[:end_at]
  
  taggable_conditions  = sanitize_sql(["#{SemanticallyTaggable::Tagging.table_name}.taggable_type = ?", base_class.name])
  taggable_conditions << sanitize_sql([" AND #{SemanticallyTaggable::Tagging.table_name}.taggable_id = ?", options.delete(:id)])  if options[:id]
  taggable_conditions << sanitize_sql([" AND #{SemanticallyTaggable::Scheme.table_name}.name = ?", scheme_name]) if scheme_name

  tagging_conditions = [
    taggable_conditions,
    start_at_conditions,
    end_at_conditions
  ].compact.reverse
  
  tag_conditions = [
    options[:conditions]        
  ].compact.reverse
  
  ## Generate joins:
  taggable_join = "INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{SemanticallyTaggable::Tagging.table_name}.taggable_id"
  taggable_join << " AND #{table_name}.#{inheritance_column} = '#{name}'" unless descends_from_active_record? # Current model is STI descendant, so add type checking to the join condition
  if scheme_name
    taggable_join << " INNER JOIN tags on tags.id = taggings.tag_id "
    taggable_join << " INNER JOIN schemes on schemes.id = tags.scheme_id "
  end

  tagging_joins = [
    taggable_join,
    scope[:joins]
  ].compact

  tag_joins = [
  ].compact

  ## Generate scope:
  tagging_scope = SemanticallyTaggable::Tagging.select("#{SemanticallyTaggable::Tagging.table_name}.tag_id, COUNT(#{SemanticallyTaggable::Tagging.table_name}.tag_id) AS tags_count")
  tag_scope = SemanticallyTaggable::Tag.select("#{SemanticallyTaggable::Tag.table_name}.*, #{SemanticallyTaggable::Tagging.table_name}.tags_count AS count").order(options[:order]).limit(options[:limit])

  # Joins and conditions
  tagging_joins.each      { |join|      tagging_scope = tagging_scope.joins(join)      }        
  tagging_conditions.each { |condition| tagging_scope = tagging_scope.where(condition) }

  tag_joins.each          { |join|      tag_scope     = tag_scope.joins(join)          }
  tag_conditions.each     { |condition| tag_scope     = tag_scope.where(condition)     }

  # GROUP BY and HAVING clauses:
  at_least  = sanitize_sql(['tags_count >= ?', options.delete(:at_least)]) if options[:at_least]
  at_most   = sanitize_sql(['tags_count <= ?', options.delete(:at_most)]) if options[:at_most]
  having    = ["COUNT(#{SemanticallyTaggable::Tagging.table_name}.tag_id) > 0", at_least, at_most].compact.join(' AND ')

  group_columns = "#{SemanticallyTaggable::Tagging.table_name}.tag_id"

  # Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
  scoped_select = "#{table_name}.#{primary_key}"
  tagging_scope = tagging_scope.where("taggings.taggable_id IN(#{select(scoped_select).to_sql})").
                                group(group_columns).
                                having(having)

  tag_scope = tag_scope.joins("JOIN (#{tagging_scope.to_sql}) AS taggings ON taggings.tag_id = tags.id")
  tag_scope
end
initialize_semantically_taggable_collection() click to toggle source
# File lib/semantically_taggable/semantically_taggable/collection.rb, line 10
def initialize_semantically_taggable_collection
  scheme_names.map(&:to_s).each do |scheme_name|
    class_eval %(
      def self.#{scheme_name.singularize}_counts(options={})
        tag_counts_on('#{scheme_name}', options)
      end

      def #{scheme_name.singularize}_counts(options = {})
        tag_counts_on('#{scheme_name}', options)
      end

      def top_#{scheme_name}(limit = 10)
        tag_counts_on('#{scheme_name}', :order => 'count desc', :limit => limit.to_i)
      end

      def self.top_#{scheme_name}(limit = 10)
        tag_counts_on('#{scheme_name}', :order => 'count desc', :limit => limit.to_i)
      end        
    )
  end        
end
semantically_taggable(*args) click to toggle source
Calls superclass method
# File lib/semantically_taggable/semantically_taggable/collection.rb, line 32
def semantically_taggable(*args)
  super(*args)
  initialize_semantically_taggable_collection
end
tag_counts_on(scheme_name, options = {}) click to toggle source
# File lib/semantically_taggable/semantically_taggable/collection.rb, line 37
def tag_counts_on(scheme_name, options = {})
  all_tag_counts(options.merge({:on => scheme_name.to_s}))
end