acts-as-taggable-on 2.0.6 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +9 -0
- data/CHANGELOG +10 -0
- data/Gemfile +2 -9
- data/Guardfile +5 -0
- data/README.rdoc +89 -66
- data/Rakefile +9 -55
- data/acts-as-taggable-on.gemspec +28 -0
- data/lib/acts-as-taggable-on/version.rb +4 -0
- data/lib/acts-as-taggable-on.rb +33 -4
- data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +4 -4
- data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +38 -43
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +146 -38
- data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +37 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +36 -11
- data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +23 -15
- data/lib/acts_as_taggable_on/tag.rb +16 -13
- data/lib/acts_as_taggable_on/tag_list.rb +13 -12
- data/lib/acts_as_taggable_on/taggable.rb +102 -0
- data/lib/acts_as_taggable_on/{acts_as_tagger.rb → tagger.rb} +3 -3
- data/lib/acts_as_taggable_on/tagging.rb +12 -2
- data/lib/acts_as_taggable_on/tags_helper.rb +2 -2
- data/lib/acts_as_taggable_on/utils.rb +34 -0
- data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +9 -2
- data/lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb +3 -1
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +300 -54
- data/spec/acts_as_taggable_on/tag_list_spec.rb +84 -61
- data/spec/acts_as_taggable_on/tag_spec.rb +51 -13
- data/spec/acts_as_taggable_on/taggable_spec.rb +261 -34
- data/spec/acts_as_taggable_on/tagger_spec.rb +36 -15
- data/spec/acts_as_taggable_on/tagging_spec.rb +2 -5
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +16 -0
- data/spec/acts_as_taggable_on/utils_spec.rb +21 -0
- data/spec/database.yml.sample +4 -2
- data/spec/generators/acts_as_taggable_on/migration/migration_generator_spec.rb +22 -0
- data/spec/models.rb +19 -1
- data/spec/schema.rb +18 -0
- data/spec/spec_helper.rb +30 -7
- data/uninstall.rb +1 -0
- metadata +137 -51
- data/VERSION +0 -1
- data/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb +0 -7
- data/generators/acts_as_taggable_on_migration/templates/migration.rb +0 -29
- data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +0 -53
- data/lib/acts_as_taggable_on/compatibility/Gemfile +0 -8
- data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +0 -17
- data/lib/acts_as_taggable_on/compatibility/postgresql.rb +0 -44
- data/spec/database.yml +0 -17
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
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
data/Guardfile
ADDED
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.
|
19
|
+
=== Rails 2.x
|
19
20
|
|
20
|
-
|
21
|
+
Not supported any more! It is time for update guys.
|
21
22
|
|
22
|
-
|
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
|
58
|
-
directory, you can run the specs for RoR 3.
|
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
|
-
|
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 =>
|
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
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
*
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
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
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
Bundler.setup :default, :development
|
4
4
|
|
5
|
-
|
6
|
-
|
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
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
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
|
data/lib/acts-as-taggable-on.rb
CHANGED
@@ -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
|
-
|
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/
|
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/
|
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.
|
14
|
+
base.initialize_acts_as_taggable_on_cache
|
15
15
|
end
|
16
16
|
|
17
17
|
module ClassMethods
|
18
|
-
def
|
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
|
-
|
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
|
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 =
|
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)])
|
70
|
-
|
71
|
-
|
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
|
-
|
87
|
-
tagging_join,
|
83
|
+
tagging_joins = [
|
88
84
|
taggable_join,
|
89
85
|
scope[:joins]
|
90
86
|
].compact
|
91
87
|
|
92
|
-
|
93
|
-
|
88
|
+
tag_joins = [
|
89
|
+
].compact
|
94
90
|
|
95
91
|
## Generate scope:
|
96
|
-
|
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
|
-
|
100
|
-
|
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(['
|
104
|
-
at_most = sanitize_sql(['
|
105
|
-
having = [at_least, at_most].compact.join(' AND ')
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
|