acts-as-taggable-on 2.0.6 → 2.3.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.
Files changed (49) hide show
  1. data/.gitignore +10 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG +10 -0
  5. data/Gemfile +2 -9
  6. data/Guardfile +5 -0
  7. data/README.rdoc +89 -66
  8. data/Rakefile +9 -55
  9. data/acts-as-taggable-on.gemspec +28 -0
  10. data/lib/acts-as-taggable-on/version.rb +4 -0
  11. data/lib/acts-as-taggable-on.rb +33 -4
  12. data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +4 -4
  13. data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +38 -43
  14. data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +146 -38
  15. data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +37 -0
  16. data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +36 -11
  17. data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +23 -15
  18. data/lib/acts_as_taggable_on/tag.rb +16 -13
  19. data/lib/acts_as_taggable_on/tag_list.rb +13 -12
  20. data/lib/acts_as_taggable_on/taggable.rb +102 -0
  21. data/lib/acts_as_taggable_on/{acts_as_tagger.rb → tagger.rb} +3 -3
  22. data/lib/acts_as_taggable_on/tagging.rb +12 -2
  23. data/lib/acts_as_taggable_on/tags_helper.rb +2 -2
  24. data/lib/acts_as_taggable_on/utils.rb +34 -0
  25. data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +9 -2
  26. data/lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb +3 -1
  27. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +300 -54
  28. data/spec/acts_as_taggable_on/tag_list_spec.rb +84 -61
  29. data/spec/acts_as_taggable_on/tag_spec.rb +51 -13
  30. data/spec/acts_as_taggable_on/taggable_spec.rb +261 -34
  31. data/spec/acts_as_taggable_on/tagger_spec.rb +36 -15
  32. data/spec/acts_as_taggable_on/tagging_spec.rb +2 -5
  33. data/spec/acts_as_taggable_on/tags_helper_spec.rb +16 -0
  34. data/spec/acts_as_taggable_on/utils_spec.rb +21 -0
  35. data/spec/database.yml.sample +4 -2
  36. data/spec/generators/acts_as_taggable_on/migration/migration_generator_spec.rb +22 -0
  37. data/spec/models.rb +19 -1
  38. data/spec/schema.rb +18 -0
  39. data/spec/spec_helper.rb +30 -7
  40. data/uninstall.rb +1 -0
  41. metadata +137 -51
  42. data/VERSION +0 -1
  43. data/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb +0 -7
  44. data/generators/acts_as_taggable_on_migration/templates/migration.rb +0 -29
  45. data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +0 -53
  46. data/lib/acts_as_taggable_on/compatibility/Gemfile +0 -8
  47. data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +0 -17
  48. data/lib/acts_as_taggable_on/compatibility/postgresql.rb +0 -44
  49. data/spec/database.yml +0 -17
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ *.log
2
+ *.sqlite3
3
+ /pkg/*
4
+ .bundle
5
+ .rvmrc
6
+ Gemfile.lock
7
+ spec/database.yml
8
+ tmp*.sw?
9
+ *.sw?
10
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --backtrace
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ script: "cp spec/database.yml.sample spec/database.yml && bundle install && bundle exec rake"
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ env:
7
+ - DB=sqlite3
8
+ - DB=mysql
9
+ - DB=postgresql
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ == 2011-08-21
2
+ * escape _ and % for mysql and postgres (@tilsammans)
3
+ * Now depends on mysql2 gem
4
+ * tagged_with :any is chainable now (@jeffreyiacono)
5
+ * tagged_with(nil) returns scoped object
6
+ * Case-insensitivity for TaggedModel.tagged_with for PostgreSQL database
7
+ * tagged_with(' ') returns scoped object
8
+ * remove warning for rails 3.1 about class_inheritable_attribute
9
+ * use ActiveRecord migration_number to avoid clashs (@atd)
10
+
1
11
  == 2010-02-17
2
12
  * Converted the plugin to be compatible with Rails3
3
13
 
data/Gemfile CHANGED
@@ -1,10 +1,3 @@
1
- source :gemcutter
1
+ source 'http://rubygems.org'
2
+ gemspec
2
3
 
3
- # Rails 3.0
4
- gem 'rails', '3.0.0.beta3'
5
- gem 'rspec', '2.0.0.beta.8'
6
- gem 'sqlite3-ruby', :require => 'sqlite3'
7
- gem 'mysql'
8
- gem 'pg'
9
- gem 'jeweler'
10
- gem 'rcov'
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb})
3
+ watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/README.rdoc CHANGED
@@ -1,4 +1,5 @@
1
1
  = ActsAsTaggableOn
2
+ {<img src="https://secure.travis-ci.org/mbleigh/acts-as-taggable-on.png" />}[http://travis-ci.org/mbleigh/acts-as-taggable-on]
2
3
 
3
4
  This plugin was originally based on Acts as Taggable on Steroids by Jonathan Viney.
4
5
  It has evolved substantially since that point, but all credit goes to him for the
@@ -15,37 +16,15 @@ was used.
15
16
 
16
17
  == Installation
17
18
 
18
- === Rails 2.3.x
19
+ === Rails 2.x
19
20
 
20
- Acts As Taggable On is tested to work in Rails 2.3.5.
21
+ Not supported any more! It is time for update guys.
21
22
 
22
- ==== Plugin
23
-
24
- Acts As Taggable On is available both as a gem and as a traditional plugin. For the
25
- traditional plugin you can install like so:
26
-
27
- script/plugin install git://github.com/mbleigh/acts-as-taggable-on.git
28
-
29
- Acts As Taggable On is also available as a gem plugin using Rails 2.1's gem dependencies.
30
- To install the gem, add this to your config/environment.rb:
31
-
32
- config.gem "acts-as-taggable-on", :source => "http://gemcutter.org", :version => '2.0.0.rc1'
33
-
34
- After that, you can run "rake gems:install" to install the gem if you don't already have it.
35
-
36
- ==== Post Installation
37
-
38
- 1. script/generate acts_as_taggable_on_migration
39
- 2. rake db:migrate
40
-
41
- === Rails 3.0
42
-
43
- Acts As Taggable On is now useable in Rails 3.0, thanks to the excellent work of Szymon Nowak
44
- and Jelle Vandebeeck.
23
+ === Rails 3.x
45
24
 
46
25
  To use it, add it to your Gemfile:
47
-
48
- gem 'acts-as-taggable-on'
26
+
27
+ gem 'acts-as-taggable-on', '~> 2.2.2'
49
28
 
50
29
  ==== Post Installation
51
30
 
@@ -54,20 +33,11 @@ To use it, add it to your Gemfile:
54
33
 
55
34
  == Testing
56
35
 
57
- Acts As Taggable On uses RSpec for its test coverage. Inside the plugin
58
- directory, you can run the specs for RoR 3.0.0 with:
36
+ Acts As Taggable On uses RSpec for its test coverage. Inside the gem
37
+ directory, you can run the specs for RoR 3.x with:
59
38
 
60
39
  rake spec
61
40
 
62
- If you want to test the plugin for Rails 2.3.x, use:
63
-
64
- rake rails2.3:spec
65
-
66
- If you already have RSpec on your application, the specs will run while using:
67
-
68
- rake spec:plugins
69
-
70
-
71
41
  == Usage
72
42
 
73
43
  class User < ActiveRecord::Base
@@ -89,6 +59,25 @@ rake spec:plugins
89
59
  User.skill_counts # => [<Tag name="joking" count=2>,<Tag name="clowning" count=1>...]
90
60
  @frankie.skill_counts
91
61
 
62
+ To preserve the order in which tags are created use acts_as_ordered_taggable:
63
+
64
+ class User < ActiveRecord::Base
65
+ # Alias for <tt>acts_as_ordered_taggable_on :tags</tt>:
66
+ acts_as_ordered_taggable
67
+ acts_as_ordered_taggable_on :skills, :interests
68
+ end
69
+
70
+ @user = User.new(:name => "Bobby")
71
+ @user.tag_list = "east, south"
72
+ @user.save
73
+
74
+ @user.tag_list = "north, east, south, west"
75
+ @user.save
76
+
77
+ @user.reload
78
+ @user.tag_list # => ["north", "east", "south", "west"]
79
+
80
+
92
81
  === Finding Tagged Objects
93
82
 
94
83
  Acts As Taggable On utilizes named_scopes to create an association for tags.
@@ -96,23 +85,33 @@ This way you can mix and match to filter down your results, and it also improves
96
85
  compatibility with the will_paginate gem:
97
86
 
98
87
  class User < ActiveRecord::Base
99
- acts_as_taggable_on :tags
100
- named_scope :by_join_date, :order => "created_at DESC"
88
+ acts_as_taggable_on :tags, :skills
89
+ scope :by_join_date, order("created_at DESC")
101
90
  end
102
91
 
103
92
  User.tagged_with("awesome").by_date
104
93
  User.tagged_with("awesome").by_date.paginate(:page => params[:page], :per_page => 20)
105
94
 
106
95
  # Find a user with matching all tags, not just one
107
- User.tagged_with(["awesome", "cool"], :match_all => :true)
108
-
96
+ User.tagged_with(["awesome", "cool"], :match_all => true)
97
+
109
98
  # Find a user with any of the tags:
110
99
  User.tagged_with(["awesome", "cool"], :any => true)
111
100
 
101
+ # Find a user that not tags with awesome or cool:
102
+ User.tagged_with(["awesome", "cool"], :exclude => true)
103
+
104
+ # Find a user with any of tags based on context:
105
+ User.tagged_with(['awesome, cool'], :on => :tags, :any => true).tagged_with(['smart', 'shy'], :on => :skills, :any => true)
106
+
107
+ You can also use :wild => true option along with :any or :exclude option. It will looking for %awesome% and %cool% in sql.
108
+
109
+ Tip: User.tagged_with([]) or '' will return [], but not all records.
110
+
112
111
  === Relationships
113
112
 
114
113
  You can find objects of the same type based on similar tags on certain contexts.
115
- Also, objects will be returned in descending order based on the total number of
114
+ Also, objects will be returned in descending order based on the total number of
116
115
  matched tags.
117
116
 
118
117
  @bobby = User.find_by_name("Bobby")
@@ -125,8 +124,8 @@ matched tags.
125
124
  @tom.skill_list # => ["hacking", "jogging", "diving"]
126
125
 
127
126
  @tom.find_related_skills # => [<User name="Bobby">,<User name="Frankie">]
128
- @bobby.find_related_skills # => [<User name="Tom">]
129
- @frankie.find_related_skills # => [<User name="Tom">]
127
+ @bobby.find_related_skills # => [<User name="Tom">]
128
+ @frankie.find_related_skills # => [<User name="Tom">]
130
129
 
131
130
  === Dynamic Tag Contexts
132
131
 
@@ -156,8 +155,25 @@ Tags can have owners:
156
155
  @some_user.tag(@some_photo, :with => "paris, normandy", :on => :locations)
157
156
  @some_user.owned_taggings
158
157
  @some_user.owned_tags
159
- @some_photo.locations_from(@some_user)
160
-
158
+ @some_photo.locations_from(@some_user) # => ["paris", "normandy"]
159
+ @some_photo.owner_tags_on(@some_user, :locations) # => [#<ActsAsTaggableOn::Tag id: 1, name: "paris">...]
160
+ @some_photo.owner_tags_on(nil, :locations) # => Ownerships equivalent to saying @some_photo.locations
161
+ @some_user.tag(@some_photo, :with => "paris, normandy", :on => :locations, :skip_save => true) #won't save @some_photo object
162
+
163
+ === Dirty objects
164
+
165
+ @bobby = User.find_by_name("Bobby")
166
+ @bobby.skill_list # => ["jogging", "diving"]
167
+
168
+ @boddy.skill_list_changed? #=> false
169
+ @boddy.changes #=> {}
170
+
171
+ @bobby.skill_list = "swimming"
172
+ @bobby.changes.should == {"skill_list"=>["jogging, diving", ["swimming"]]}
173
+ @boddy.skill_list_changed? #=> true
174
+
175
+ @bobby.skill_list_change.should == ["jogging, diving", ["swimming"]]
176
+
161
177
  === Tag cloud calculations
162
178
 
163
179
  To construct tag clouds, the frequency of each tag needs to be calculated.
@@ -198,24 +214,31 @@ CSS:
198
214
  .css3 { font-size: 1.4em; }
199
215
  .css4 { font-size: 1.6em; }
200
216
 
217
+ == Configuration
218
+
219
+ If you would like to remove unused tag objects after removing taggings, add
220
+
221
+ ActsAsTaggableOn.remove_unused_tags = true
222
+
223
+ If you want force tags to be saved downcased:
224
+
225
+ ActsAsTaggableOn.force_lowercase = true
226
+
227
+ If you want tags to be saved parametrized (you can redefine to_param as well):
228
+
229
+ ActsAsTaggableOn.force_parameterize = true
230
+
231
+
201
232
  == Contributors
202
233
 
203
- * TomEric (i76) - Maintainer
204
- * Michael Bleigh - Original Author
205
- * Szymon Nowak - Rails 3.0 compatibility
206
- * Jelle Vandebeeck - Rails 3.0 compatibility
207
- * Brendan Lim - Related Objects
208
- * Pradeep Elankumaran - Taggers
209
- * Sinclair Bain - Patch King
210
-
211
- === Patch Contributors
212
-
213
- * tristanzdunn - Related objects of other classes
214
- * azabaj - Fixed migrate down
215
- * Peter Cooper - named_scope fix
216
- * slainer68 - STI fix
217
- * harrylove - migration instructions and fix-ups
218
- * lawrencepit - cached tag work
219
- * sobrinho - fixed tag_cloud helper
220
-
221
- Copyright (c) 2007-2010 Michael Bleigh (http://mbleigh.com/) and Intridea Inc. (http://intridea.com/), released under the MIT license
234
+ We have a long list of valued contributors. {Check them all}[https://github.com/mbleigh/acts-as-taggable-on/contributors]
235
+
236
+ == Maintainers
237
+
238
+ * Artem Kramarenko (artemk)
239
+
240
+ == Author
241
+
242
+ * Michael Bleigh
243
+
244
+ Copyright (c) 2007-2011 Michael Bleigh (http://mbleigh.com/) and Intridea Inc. (http://intridea.com/), released under the MIT license
data/Rakefile CHANGED
@@ -1,59 +1,13 @@
1
- begin
2
- # Rspec 1.3.0
3
- require 'spec/rake/spectask'
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup :default, :development
4
4
 
5
- desc 'Default: run specs'
6
- task :default => :spec
7
- Spec::Rake::SpecTask.new do |t|
8
- t.spec_files = FileList["spec/**/*_spec.rb"]
9
- end
5
+ desc 'Default: run specs'
6
+ task :default => :spec
10
7
 
11
- Spec::Rake::SpecTask.new('rcov') do |t|
12
- t.spec_files = FileList["spec/**/*_spec.rb"]
13
- t.rcov = true
14
- t.rcov_opts = ['--exclude', 'spec']
15
- end
16
-
17
- rescue LoadError
18
- # Rspec 2.0
19
- require 'rspec/core/rake_task'
20
-
21
- desc 'Default: run specs'
22
- task :default => :spec
23
- Rspec::Core::RakeTask.new do |t|
24
- t.pattern = "spec/**/*_spec.rb"
25
- end
26
-
27
- Rspec::Core::RakeTask.new('rcov') do |t|
28
- t.pattern = "spec/**/*_spec.rb"
29
- t.rcov = true
30
- t.rcov_opts = ['--exclude', 'spec']
31
- end
32
-
33
- rescue LoadError
34
- puts "Rspec not available. Install it with: gem install rspec"
35
- end
36
-
37
- namespace 'rails2.3' do
38
- task :spec do
39
- gemfile = File.join(File.dirname(__FILE__), 'lib', 'acts_as_taggable_on', 'compatibility', 'Gemfile')
40
- ENV['BUNDLE_GEMFILE'] = gemfile
41
- Rake::Task['spec'].invoke
42
- end
8
+ require 'rspec/core/rake_task'
9
+ RSpec::Core::RakeTask.new do |t|
10
+ t.pattern = "spec/**/*_spec.rb"
43
11
  end
44
12
 
45
- begin
46
- require 'jeweler'
47
- Jeweler::Tasks.new do |gemspec|
48
- gemspec.name = "acts-as-taggable-on"
49
- gemspec.summary = "ActsAsTaggableOn is a tagging plugin for Rails that provides multiple tagging contexts on a single model."
50
- gemspec.description = "With ActsAsTaggableOn, you could tag a single model on several contexts, such as skills, interests, and awards. It also provides other advanced functionality."
51
- gemspec.email = "michael@intridea.com"
52
- gemspec.homepage = "http://github.com/mbleigh/acts-as-taggable-on"
53
- gemspec.authors = ["Michael Bleigh"]
54
- gemspec.files = FileList["[A-Z]*", "{generators,lib,spec,rails}/**/*"] - FileList["**/*.log"]
55
- end
56
- Jeweler::GemcutterTasks.new
57
- rescue LoadError
58
- puts "Jeweler not available. Install it with: gem install jeweler"
59
- end
13
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,28 @@
1
+ $:.push File.dirname(__FILE__) + '/lib'
2
+ require 'acts-as-taggable-on/version'
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = %q{acts-as-taggable-on}
6
+ gem.authors = ["Michael Bleigh"]
7
+ gem.date = %q{2012-01-06}
8
+ gem.description = %q{With ActsAsTaggableOn, you can tag a single model on several contexts, such as skills, interests, and awards. It also provides other advanced functionality.}
9
+ gem.summary = "Advanced tagging for Rails."
10
+ gem.email = %q{michael@intridea.com}
11
+ gem.homepage = ''
12
+
13
+ gem.add_runtime_dependency 'rails', '~> 3.0'
14
+ gem.add_development_dependency 'rspec', '~> 2.6'
15
+ gem.add_development_dependency 'ammeter', '~> 0.1.3'
16
+ gem.add_development_dependency 'sqlite3'
17
+ gem.add_development_dependency 'mysql2', '~> 0.3.7'
18
+ gem.add_development_dependency 'pg'
19
+ gem.add_development_dependency 'guard'
20
+ gem.add_development_dependency 'guard-rspec'
21
+
22
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ gem.files = `git ls-files`.split("\n")
24
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ gem.name = "acts-as-taggable-on"
26
+ gem.require_paths = ['lib']
27
+ gem.version = ActsAsTaggableOn::VERSION
28
+ end
@@ -0,0 +1,4 @@
1
+ module ActsAsTaggableOn
2
+ VERSION = '2.3.0'
3
+ end
4
+
@@ -1,18 +1,45 @@
1
1
  require "active_record"
2
+ require "active_record/version"
2
3
  require "action_view"
3
4
 
5
+ require "digest/sha1"
6
+
4
7
  $LOAD_PATH.unshift(File.dirname(__FILE__))
5
8
 
6
- require "acts_as_taggable_on/compatibility/active_record_backports" if ActiveRecord::VERSION::MAJOR < 3
9
+ module ActsAsTaggableOn
10
+ mattr_accessor :delimiter
11
+ @@delimiter = ','
12
+
13
+ mattr_accessor :force_lowercase
14
+ @@force_lowercase = false
15
+
16
+ mattr_accessor :force_parameterize
17
+ @@force_parameterize = false
18
+
19
+ mattr_accessor :remove_unused_tags
20
+ self.remove_unused_tags = false
21
+
22
+ def self.glue
23
+ @@delimiter.ends_with?(" ") ? @@delimiter : "#{@@delimiter} "
24
+ end
25
+
26
+ def self.setup
27
+ yield self
28
+ end
29
+ end
30
+
31
+
32
+ require "acts_as_taggable_on/utils"
7
33
 
8
- require "acts_as_taggable_on/acts_as_taggable_on"
34
+ require "acts_as_taggable_on/taggable"
9
35
  require "acts_as_taggable_on/acts_as_taggable_on/core"
10
36
  require "acts_as_taggable_on/acts_as_taggable_on/collection"
11
37
  require "acts_as_taggable_on/acts_as_taggable_on/cache"
12
38
  require "acts_as_taggable_on/acts_as_taggable_on/ownership"
13
39
  require "acts_as_taggable_on/acts_as_taggable_on/related"
40
+ require "acts_as_taggable_on/acts_as_taggable_on/dirty"
14
41
 
15
- require "acts_as_taggable_on/acts_as_tagger"
42
+ require "acts_as_taggable_on/tagger"
16
43
  require "acts_as_taggable_on/tag"
17
44
  require "acts_as_taggable_on/tag_list"
18
45
  require "acts_as_taggable_on/tags_helper"
@@ -20,6 +47,7 @@ require "acts_as_taggable_on/tagging"
20
47
 
21
48
  $LOAD_PATH.shift
22
49
 
50
+
23
51
  if defined?(ActiveRecord::Base)
24
52
  ActiveRecord::Base.extend ActsAsTaggableOn::Taggable
25
53
  ActiveRecord::Base.send :include, ActsAsTaggableOn::Tagger
@@ -27,4 +55,5 @@ end
27
55
 
28
56
  if defined?(ActionView::Base)
29
57
  ActionView::Base.send :include, ActsAsTaggableOn::TagsHelper
30
- end
58
+ end
59
+
@@ -11,11 +11,11 @@ module ActsAsTaggableOn::Taggable
11
11
  before_save :save_cached_tag_list
12
12
  end
13
13
 
14
- base.intialize_acts_as_taggable_on_cache
14
+ base.initialize_acts_as_taggable_on_cache
15
15
  end
16
16
 
17
17
  module ClassMethods
18
- def intialize_acts_as_taggable_on_cache
18
+ def initialize_acts_as_taggable_on_cache
19
19
  tag_types.map(&:to_s).each do |tag_type|
20
20
  class_eval %(
21
21
  def self.caching_#{tag_type.singularize}_list?
@@ -27,7 +27,7 @@ module ActsAsTaggableOn::Taggable
27
27
 
28
28
  def acts_as_taggable_on(*args)
29
29
  super(*args)
30
- intialize_acts_as_taggable_on_cache
30
+ initialize_acts_as_taggable_on_cache
31
31
  end
32
32
 
33
33
  def caching_tag_list_on?(context)
@@ -40,7 +40,7 @@ module ActsAsTaggableOn::Taggable
40
40
  tag_types.map(&:to_s).each do |tag_type|
41
41
  if self.class.send("caching_#{tag_type.singularize}_list?")
42
42
  if tag_list_cache_set_on(tag_type)
43
- list = tag_list_cache_on(tag_type.singularize).to_a.flatten.compact.join(', ')
43
+ list = tag_list_cache_on(tag_type).to_a.flatten.compact.join(', ')
44
44
  self["cached_#{tag_type.singularize}_list"] = list
45
45
  end
46
46
  end
@@ -53,73 +53,68 @@ module ActsAsTaggableOn::Taggable
53
53
  def all_tag_counts(options = {})
54
54
  options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :on, :id
55
55
 
56
- scope = if ActiveRecord::VERSION::MAJOR >= 3
57
- {}
58
- else
59
- scope(:find) || {}
60
- end
56
+ scope = {}
61
57
 
62
58
  ## Generate conditions:
63
59
  options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]
64
-
60
+
65
61
  start_at_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
66
62
  end_at_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
67
-
63
+
68
64
  taggable_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.taggable_type = ?", base_class.name])
69
- taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = ?", options.delete(:id)]) if options[:id]
70
-
71
- conditions = [
65
+ taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = ?", options.delete(:id)]) if options[:id]
66
+ taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", options.delete(:on).to_s]) if options[:on]
67
+
68
+ tagging_conditions = [
72
69
  taggable_conditions,
73
- options[:conditions],
74
70
  scope[:conditions],
75
71
  start_at_conditions,
76
72
  end_at_conditions
77
73
  ].compact.reverse
78
74
 
75
+ tag_conditions = [
76
+ options[:conditions]
77
+ ].compact.reverse
78
+
79
79
  ## Generate joins:
80
- tagging_join = "LEFT OUTER JOIN #{ActsAsTaggableOn::Tagging.table_name} ON #{ActsAsTaggableOn::Tag.table_name}.id = #{ActsAsTaggableOn::Tagging.table_name}.tag_id"
81
- tagging_join << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", options.delete(:on).to_s]) if options[:on]
82
-
83
80
  taggable_join = "INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id"
84
81
  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
85
82
 
86
- joins = [
87
- tagging_join,
83
+ tagging_joins = [
88
84
  taggable_join,
89
85
  scope[:joins]
90
86
  ].compact
91
87
 
92
- joins = joins.reverse if ActiveRecord::VERSION::MAJOR < 3
93
-
88
+ tag_joins = [
89
+ ].compact
94
90
 
95
91
  ## Generate scope:
96
- scope = ActsAsTaggableOn::Tag.scoped(:select => "#{ActsAsTaggableOn::Tag.table_name}.*, COUNT(*) AS count").order(options[:order]).limit(options[:limit])
97
-
92
+ tagging_scope = ActsAsTaggableOn::Tagging.select("#{ActsAsTaggableOn::Tagging.table_name}.tag_id, COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) AS tags_count")
93
+ tag_scope = ActsAsTaggableOn::Tag.select("#{ActsAsTaggableOn::Tag.table_name}.*, #{ActsAsTaggableOn::Tagging.table_name}.tags_count AS count").order(options[:order]).limit(options[:limit])
94
+
98
95
  # Joins and conditions
99
- joins.each { |join| scope = scope.joins(join) }
100
- conditions.each { |condition| scope = scope.where(condition) }
101
-
96
+ tagging_joins.each { |join| tagging_scope = tagging_scope.joins(join) }
97
+ tagging_conditions.each { |condition| tagging_scope = tagging_scope.where(condition) }
98
+
99
+ tag_joins.each { |join| tag_scope = tag_scope.joins(join) }
100
+ tag_conditions.each { |condition| tag_scope = tag_scope.where(condition) }
101
+
102
102
  # GROUP BY and HAVING clauses:
103
- at_least = sanitize_sql(['COUNT(*) >= ?', options.delete(:at_least)]) if options[:at_least]
104
- at_most = sanitize_sql(['COUNT(*) <= ?', options.delete(:at_most)]) if options[:at_most]
105
- having = [at_least, at_most].compact.join(' AND ')
106
-
107
- if ActiveRecord::VERSION::MAJOR >= 3
108
- # Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
109
- scoped_select = "#{table_name}.#{primary_key}"
110
- scope = scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{select(scoped_select).to_sql})")
111
-
112
- # We have having() in RoR 3.0 so use it:
113
- having = having.blank? ? "COUNT(*) > 0" : "COUNT(*) > 0 AND #{having}"
114
- scope = scope.group(grouped_column_names_for(ActsAsTaggableOn::Tag)).having(having)
115
- else
116
- # Having is not available in 2.3.x:
117
- group_by = "#{grouped_column_names_for(ActsAsTaggableOn::Tag)} HAVING COUNT(*) > 0"
118
- group_by << " AND #{having}" unless having.blank?
119
- scope = scope.group(group_by)
120
- end
121
-
122
- scope
103
+ at_least = sanitize_sql(['tags_count >= ?', options.delete(:at_least)]) if options[:at_least]
104
+ at_most = sanitize_sql(['tags_count <= ?', options.delete(:at_most)]) if options[:at_most]
105
+ having = ["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) > 0", at_least, at_most].compact.join(' AND ')
106
+
107
+ group_columns = "#{ActsAsTaggableOn::Tagging.table_name}.tag_id"
108
+
109
+ # Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
110
+ scoped_select = "#{table_name}.#{primary_key}"
111
+ tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{select(scoped_select).to_sql})").
112
+ group(group_columns).
113
+ having(having)
114
+
115
+
116
+ 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")
117
+ tag_scope
123
118
  end
124
119
  end
125
120