acts-as-taggable-on 2.0.0 → 2.1.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.
- data/.gitignore +7 -0
- data/.travis.yml +10 -0
- data/Gemfile +2 -5
- data/Guardfile +5 -0
- data/README.rdoc +19 -16
- data/Rakefile +9 -55
- data/VERSION +1 -1
- data/acts-as-taggable-on.gemspec +27 -0
- data/lib/acts-as-taggable-on/version.rb +4 -0
- data/lib/acts-as-taggable-on.rb +8 -2
- data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +6 -6
- data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +72 -31
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +67 -32
- data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +16 -12
- data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +18 -9
- data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +16 -6
- data/lib/acts_as_taggable_on/acts_as_tagger.rb +2 -2
- data/lib/acts_as_taggable_on/compatibility/Gemfile +3 -1
- data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +5 -1
- data/lib/acts_as_taggable_on/tag.rb +73 -57
- data/lib/acts_as_taggable_on/tag_list.rb +79 -78
- data/lib/acts_as_taggable_on/tagging.rb +19 -18
- data/lib/acts_as_taggable_on/tags_helper.rb +12 -12
- data/lib/acts_as_taggable_on/utils.rb +31 -0
- data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +3 -2
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +25 -2
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +3 -3
- data/spec/acts_as_taggable_on/tag_list_spec.rb +3 -3
- data/spec/acts_as_taggable_on/tag_spec.rb +41 -21
- data/spec/acts_as_taggable_on/taggable_spec.rb +69 -12
- data/spec/acts_as_taggable_on/tagger_spec.rb +5 -5
- data/spec/acts_as_taggable_on/tagging_spec.rb +7 -7
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +3 -3
- data/spec/acts_as_taggable_on/utils_spec.rb +22 -0
- data/spec/database.yml.sample +19 -0
- data/spec/models.rb +5 -0
- data/spec/schema.rb +6 -0
- data/spec/spec_helper.rb +60 -33
- data/uninstall.rb +1 -0
- metadata +130 -15
- /data/{spec/spec.opts → .rspec} +0 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/Guardfile
ADDED
data/README.rdoc
CHANGED
|
@@ -38,21 +38,21 @@ After that, you can run "rake gems:install" to install the gem if you don't alre
|
|
|
38
38
|
1. script/generate acts_as_taggable_on_migration
|
|
39
39
|
2. rake db:migrate
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
=== Rails 3.0
|
|
42
42
|
|
|
43
43
|
Acts As Taggable On is now useable in Rails 3.0, thanks to the excellent work of Szymon Nowak
|
|
44
44
|
and Jelle Vandebeeck.
|
|
45
45
|
|
|
46
46
|
To use it, add it to your Gemfile:
|
|
47
47
|
|
|
48
|
-
gem 'acts-as-taggable-on'
|
|
48
|
+
gem 'acts-as-taggable-on'
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
==== Post Installation
|
|
51
51
|
|
|
52
52
|
1. rails generate acts_as_taggable_on:migration
|
|
53
53
|
2. rake db:migrate
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
== Testing
|
|
56
56
|
|
|
57
57
|
Acts As Taggable On uses RSpec for its test coverage. Inside the plugin
|
|
58
58
|
directory, you can run the specs for RoR 3.0.0 with:
|
|
@@ -68,7 +68,7 @@ If you already have RSpec on your application, the specs will run while using:
|
|
|
68
68
|
rake spec:plugins
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
== Usage
|
|
72
72
|
|
|
73
73
|
class User < ActiveRecord::Base
|
|
74
74
|
# Alias for <tt>acts_as_taggable_on :tags</tt>:
|
|
@@ -89,14 +89,14 @@ rake spec:plugins
|
|
|
89
89
|
User.skill_counts # => [<Tag name="joking" count=2>,<Tag name="clowning" count=1>...]
|
|
90
90
|
@frankie.skill_counts
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
=== Finding Tagged Objects
|
|
93
93
|
|
|
94
94
|
Acts As Taggable On utilizes named_scopes to create an association for tags.
|
|
95
95
|
This way you can mix and match to filter down your results, and it also improves
|
|
96
96
|
compatibility with the will_paginate gem:
|
|
97
97
|
|
|
98
98
|
class User < ActiveRecord::Base
|
|
99
|
-
acts_as_taggable_on :tags
|
|
99
|
+
acts_as_taggable_on :tags, :skills
|
|
100
100
|
named_scope :by_join_date, :order => "created_at DESC"
|
|
101
101
|
end
|
|
102
102
|
|
|
@@ -108,8 +108,11 @@ compatibility with the will_paginate gem:
|
|
|
108
108
|
|
|
109
109
|
# Find a user with any of the tags:
|
|
110
110
|
User.tagged_with(["awesome", "cool"], :any => true)
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
|
|
112
|
+
# Find a user with any of tags based on context:
|
|
113
|
+
User.tagged_with(['awesome, cool'], :on => :tags, :any => true).tagged_with(['smart', 'shy'], :on => :skills, :any => true)
|
|
114
|
+
|
|
115
|
+
=== Relationships
|
|
113
116
|
|
|
114
117
|
You can find objects of the same type based on similar tags on certain contexts.
|
|
115
118
|
Also, objects will be returned in descending order based on the total number of
|
|
@@ -128,7 +131,7 @@ matched tags.
|
|
|
128
131
|
@bobby.find_related_skills # => [<User name="Tom">]
|
|
129
132
|
@frankie.find_related_skills # => [<User name="Tom">]
|
|
130
133
|
|
|
131
|
-
|
|
134
|
+
=== Dynamic Tag Contexts
|
|
132
135
|
|
|
133
136
|
In addition to the generated tag contexts in the definition, it is also possible
|
|
134
137
|
to allow for dynamic tag contexts (this could be user generated tag contexts!)
|
|
@@ -139,9 +142,9 @@ to allow for dynamic tag contexts (this could be user generated tag contexts!)
|
|
|
139
142
|
@user.save
|
|
140
143
|
@user.tags_on(:customs) # => [<Tag name='same'>,...]
|
|
141
144
|
@user.tag_counts_on(:customs)
|
|
142
|
-
User.
|
|
145
|
+
User.tagged_with("same", :on => :customs) # => [@user]
|
|
143
146
|
|
|
144
|
-
|
|
147
|
+
=== Tag Ownership
|
|
145
148
|
|
|
146
149
|
Tags can have owners:
|
|
147
150
|
|
|
@@ -158,7 +161,7 @@ Tags can have owners:
|
|
|
158
161
|
@some_user.owned_tags
|
|
159
162
|
@some_photo.locations_from(@some_user)
|
|
160
163
|
|
|
161
|
-
|
|
164
|
+
=== Tag cloud calculations
|
|
162
165
|
|
|
163
166
|
To construct tag clouds, the frequency of each tag needs to be calculated.
|
|
164
167
|
Because we specified +acts_as_taggable_on+ on the <tt>User</tt> class, we can
|
|
@@ -174,7 +177,7 @@ Here is an example that generates a tag cloud.
|
|
|
174
177
|
Helper:
|
|
175
178
|
|
|
176
179
|
module PostsHelper
|
|
177
|
-
include TagsHelper
|
|
180
|
+
include ActsAsTaggableOn::TagsHelper
|
|
178
181
|
end
|
|
179
182
|
|
|
180
183
|
Controller:
|
|
@@ -198,7 +201,7 @@ CSS:
|
|
|
198
201
|
.css3 { font-size: 1.4em; }
|
|
199
202
|
.css4 { font-size: 1.6em; }
|
|
200
203
|
|
|
201
|
-
|
|
204
|
+
== Contributors
|
|
202
205
|
|
|
203
206
|
* TomEric (i76) - Maintainer
|
|
204
207
|
* Michael Bleigh - Original Author
|
|
@@ -208,7 +211,7 @@ CSS:
|
|
|
208
211
|
* Pradeep Elankumaran - Taggers
|
|
209
212
|
* Sinclair Bain - Patch King
|
|
210
213
|
|
|
211
|
-
|
|
214
|
+
=== Patch Contributors
|
|
212
215
|
|
|
213
216
|
* tristanzdunn - Related objects of other classes
|
|
214
217
|
* azabaj - Fixed migrate down
|
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
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.0.
|
|
1
|
+
2.0.6
|
|
@@ -0,0 +1,27 @@
|
|
|
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{2010-05-19}
|
|
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'
|
|
14
|
+
gem.add_development_dependency 'rspec', '~> 2.5'
|
|
15
|
+
gem.add_development_dependency 'sqlite3'
|
|
16
|
+
gem.add_development_dependency 'mysql2', '< 0.3'
|
|
17
|
+
gem.add_development_dependency 'pg'
|
|
18
|
+
gem.add_development_dependency 'guard'
|
|
19
|
+
gem.add_development_dependency 'guard-rspec'
|
|
20
|
+
|
|
21
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
22
|
+
gem.files = `git ls-files`.split("\n")
|
|
23
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
24
|
+
gem.name = "acts-as-taggable-on"
|
|
25
|
+
gem.require_paths = ['lib']
|
|
26
|
+
gem.version = ActsAsTaggableOn::VERSION
|
|
27
|
+
end
|
data/lib/acts-as-taggable-on.rb
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
require "active_record"
|
|
2
|
+
require "active_record/version"
|
|
2
3
|
require "action_view"
|
|
4
|
+
RAILS_3 = ::ActiveRecord::VERSION::MAJOR >= 3
|
|
3
5
|
|
|
4
6
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
5
7
|
|
|
6
|
-
require "acts_as_taggable_on/compatibility/active_record_backports"
|
|
8
|
+
require "acts_as_taggable_on/compatibility/active_record_backports" unless RAILS_3
|
|
9
|
+
|
|
10
|
+
require "acts_as_taggable_on/utils"
|
|
7
11
|
|
|
8
12
|
require "acts_as_taggable_on/acts_as_taggable_on"
|
|
9
13
|
require "acts_as_taggable_on/acts_as_taggable_on/core"
|
|
@@ -12,6 +16,7 @@ require "acts_as_taggable_on/acts_as_taggable_on/cache"
|
|
|
12
16
|
require "acts_as_taggable_on/acts_as_taggable_on/ownership"
|
|
13
17
|
require "acts_as_taggable_on/acts_as_taggable_on/related"
|
|
14
18
|
|
|
19
|
+
#require "acts_as_taggable_on/utils"
|
|
15
20
|
require "acts_as_taggable_on/acts_as_tagger"
|
|
16
21
|
require "acts_as_taggable_on/tag"
|
|
17
22
|
require "acts_as_taggable_on/tag_list"
|
|
@@ -20,11 +25,12 @@ require "acts_as_taggable_on/tagging"
|
|
|
20
25
|
|
|
21
26
|
$LOAD_PATH.shift
|
|
22
27
|
|
|
28
|
+
|
|
23
29
|
if defined?(ActiveRecord::Base)
|
|
24
30
|
ActiveRecord::Base.extend ActsAsTaggableOn::Taggable
|
|
25
31
|
ActiveRecord::Base.send :include, ActsAsTaggableOn::Tagger
|
|
26
32
|
end
|
|
27
33
|
|
|
28
34
|
if defined?(ActionView::Base)
|
|
29
|
-
ActionView::Base.send :include, TagsHelper
|
|
35
|
+
ActionView::Base.send :include, ActsAsTaggableOn::TagsHelper
|
|
30
36
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module ActsAsTaggableOn::Taggable
|
|
2
2
|
module Cache
|
|
3
3
|
def self.included(base)
|
|
4
|
-
# Skip adding caching capabilities if no cache columns exist
|
|
5
|
-
return unless base.tag_types.any? { |context| base.column_names.include?("cached_#{context.to_s.singularize}_list") }
|
|
4
|
+
# Skip adding caching capabilities if table not exists or no cache columns exist
|
|
5
|
+
return unless base.table_exists? && base.tag_types.any? { |context| base.column_names.include?("cached_#{context.to_s.singularize}_list") }
|
|
6
6
|
|
|
7
7
|
base.send :include, ActsAsTaggableOn::Taggable::Cache::InstanceMethods
|
|
8
8
|
base.extend ActsAsTaggableOn::Taggable::Cache::ClassMethods
|
|
@@ -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)
|
|
@@ -50,4 +50,4 @@ module ActsAsTaggableOn::Taggable
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
|
-
end
|
|
53
|
+
end
|
|
@@ -53,39 +53,80 @@ 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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
conditions = [
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
]
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
56
|
+
scope = if ActiveRecord::VERSION::MAJOR >= 3
|
|
57
|
+
{}
|
|
58
|
+
else
|
|
59
|
+
scope(:find) || {}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
## Generate conditions:
|
|
63
|
+
options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]
|
|
64
|
+
|
|
65
|
+
start_at_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
|
|
66
|
+
end_at_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
|
|
67
|
+
|
|
68
|
+
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
|
+
taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", options.delete(:on).to_s]) if options[:on]
|
|
71
|
+
|
|
72
|
+
tagging_conditions = [
|
|
73
|
+
taggable_conditions,
|
|
74
|
+
scope[:conditions],
|
|
75
|
+
start_at_conditions,
|
|
76
|
+
end_at_conditions
|
|
77
|
+
].compact.reverse
|
|
78
|
+
|
|
79
|
+
tag_conditions = [
|
|
80
|
+
options[:conditions]
|
|
81
|
+
].compact.reverse
|
|
82
|
+
|
|
83
|
+
## Generate joins:
|
|
84
|
+
taggable_join = "INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id"
|
|
85
|
+
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
|
|
86
|
+
|
|
87
|
+
tagging_joins = [
|
|
88
|
+
taggable_join,
|
|
89
|
+
scope[:joins]
|
|
90
|
+
].compact
|
|
91
|
+
|
|
92
|
+
tag_joins = [
|
|
93
|
+
].compact
|
|
94
|
+
|
|
95
|
+
[tagging_joins, tag_joins].each(&:reverse!) if ActiveRecord::VERSION::MAJOR < 3
|
|
81
96
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
97
|
+
## Generate scope:
|
|
98
|
+
tagging_scope = ActsAsTaggableOn::Tagging.select("#{ActsAsTaggableOn::Tagging.table_name}.tag_id, COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) AS tags_count")
|
|
99
|
+
tag_scope = ActsAsTaggableOn::Tag.select("#{ActsAsTaggableOn::Tag.table_name}.*, #{ActsAsTaggableOn::Tagging.table_name}.tags_count AS count").order(options[:order]).limit(options[:limit])
|
|
100
|
+
|
|
101
|
+
# Joins and conditions
|
|
102
|
+
tagging_joins.each { |join| tagging_scope = tagging_scope.joins(join) }
|
|
103
|
+
tagging_conditions.each { |condition| tagging_scope = tagging_scope.where(condition) }
|
|
104
|
+
|
|
105
|
+
tag_joins.each { |join| tag_scope = tag_scope.joins(join) }
|
|
106
|
+
tag_conditions.each { |condition| tag_scope = tag_scope.where(condition) }
|
|
107
|
+
|
|
108
|
+
# GROUP BY and HAVING clauses:
|
|
109
|
+
at_least = sanitize_sql(['tags_count >= ?', options.delete(:at_least)]) if options[:at_least]
|
|
110
|
+
at_most = sanitize_sql(['tags_count <= ?', options.delete(:at_most)]) if options[:at_most]
|
|
111
|
+
having = ["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) > 0", at_least, at_most].compact.join(' AND ')
|
|
112
|
+
|
|
113
|
+
group_columns = "#{ActsAsTaggableOn::Tagging.table_name}.tag_id"
|
|
114
|
+
|
|
115
|
+
if ActiveRecord::VERSION::MAJOR >= 3
|
|
116
|
+
# Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
|
|
117
|
+
scoped_select = "#{table_name}.#{primary_key}"
|
|
118
|
+
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{select(scoped_select).to_sql})").
|
|
119
|
+
group(group_columns).
|
|
120
|
+
having(having)
|
|
121
|
+
else
|
|
122
|
+
# Having is not available in 2.3.x:
|
|
123
|
+
group_by = "#{group_columns} HAVING COUNT(*) > 0"
|
|
124
|
+
group_by << " AND #{having}" unless having.blank?
|
|
125
|
+
tagging_scope = tagging_scope.group(group_by)
|
|
126
|
+
end
|
|
87
127
|
|
|
88
|
-
|
|
128
|
+
tag_scope = tag_scope.joins("JOIN (#{tagging_scope.to_sql}) AS taggings ON taggings.tag_id = tags.id")
|
|
129
|
+
tag_scope
|
|
89
130
|
end
|
|
90
131
|
end
|
|
91
132
|
|