Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored to go back to sub selects #359

Merged
merged 2 commits into from
May 15, 2013
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 28 additions & 29 deletions lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def self.included(base)
base.extend ActsAsTaggableOn::Taggable::Collection::ClassMethods
base.initialize_acts_as_taggable_on_collection
end

module ClassMethods
def initialize_acts_as_taggable_on_collection
tag_types.map(&:to_s).each do |tag_type|
Expand All @@ -24,16 +24,16 @@ def top_#{tag_type}(limit = 10)

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

def acts_as_taggable_on(*args)
super(*args)
initialize_acts_as_taggable_on_collection
end

def tag_counts_on(context, options = {})
all_tag_counts(options.merge({:on => context.to_s}))
end
Expand Down Expand Up @@ -86,12 +86,13 @@ def all_tags(options = {})
group_columns = "#{ActsAsTaggableOn::Tagging.table_name}.tag_id"

# Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
ids = select("#{table_name}.#{primary_key}").map(&:id)
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(?)", ids).group(group_columns)

tag_scope.joins("JOIN (#{tagging_scope.to_sql}) AS #{ActsAsTaggableOn::Tagging.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id")
scoped_select = "#{table_name}.#{primary_key}"
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{select(scoped_select).to_sql})").group(group_columns)

tag_scope = tag_scope.joins("JOIN (#{tagging_scope.to_sql}) AS #{ActsAsTaggableOn::Tagging.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id")
tag_scope
end

##
# Calculate the tag counts for all tags.
#
Expand All @@ -110,29 +111,29 @@ def all_tag_counts(options = {})
scope = {}

## Generate conditions:
options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]
options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]

start_at_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
end_at_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]

taggable_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.taggable_type = ?", base_class.name])
taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = ?", options.delete(:id)]) if options[:id]
taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = ?", options[:id]]) if options[:id]
taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", options.delete(:on).to_s]) if options[:on]

tagging_conditions = [
taggable_conditions,
scope[:conditions],
start_at_conditions,
end_at_conditions
].compact.reverse

tag_conditions = [
options[:conditions]
options[:conditions]
].compact.reverse

## Generate joins:
taggable_join = "INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{ActsAsTaggableOn::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
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

tagging_joins = [
taggable_join,
Expand All @@ -144,10 +145,10 @@ def all_tag_counts(options = {})

## Generate scope:
tagging_scope = ActsAsTaggableOn::Tagging.select("#{ActsAsTaggableOn::Tagging.table_name}.tag_id, COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) AS tags_count")
tag_scope = ActsAsTaggableOn::Tag.select("#{ActsAsTaggableOn::Tag.table_name}.*, #{ActsAsTaggableOn::Tagging.table_name}.tags_count AS count").order(options[:order]).limit(options[:limit])
tag_scope = ActsAsTaggableOn::Tag.select("#{ActsAsTaggableOn::Tag.table_name}.*, #{ActsAsTaggableOn::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_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) }
Expand All @@ -156,25 +157,23 @@ def all_tag_counts(options = {})
# GROUP BY and HAVING clauses:
at_least = sanitize_sql(["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) >= ?", options.delete(:at_least)]) if options[:at_least]
at_most = sanitize_sql(["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) <= ?", options.delete(:at_most)]) if options[:at_most]
having = ["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) > 0", at_least, at_most].compact.join(' AND ')
having = ["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) > 0", at_least, at_most].compact.join(' AND ')

group_columns = "#{ActsAsTaggableOn::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}"
select_query = "#{select(scoped_select).to_sql}"
unless options[: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("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{select(scoped_select).to_sql})")
end

res = ActiveRecord::Base.connection.select_all(select_query).map { |item| item.values }.flatten.compact.join(",")
res = "NULL" if res.blank?

tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{res})")
tagging_scope = tagging_scope.group(group_columns).having(having)

tag_scope = tag_scope.joins("JOIN (#{tagging_scope.to_sql}) AS #{ActsAsTaggableOn::Tagging.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id")
tag_scope
end
end

module InstanceMethods
def tag_counts_on(context, options={})
self.class.tag_counts_on(context, options.merge(:id => id))
Expand Down