acts-as-taggable-on 2.4.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +13 -4
  3. data/Appraisals +8 -4
  4. data/CHANGELOG.md +47 -0
  5. data/Gemfile +7 -1
  6. data/README.md +21 -11
  7. data/Rakefile +21 -3
  8. data/UPGRADING +7 -0
  9. data/acts-as-taggable-on.gemspec +5 -5
  10. data/{lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb → db/migrate/1_acts_as_taggable_on_migration.rb} +0 -0
  11. data/db/migrate/2_add_missing_unique_indices.rb +21 -0
  12. data/gemfiles/{rails_3.gemfile → rails_3.2.gemfile} +1 -2
  13. data/gemfiles/rails_4.0.gemfile +7 -0
  14. data/gemfiles/rails_4.1.gemfile +7 -0
  15. data/lib/acts-as-taggable-on.rb +9 -13
  16. data/lib/acts_as_taggable_on.rb +6 -0
  17. data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +49 -20
  18. data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +42 -32
  19. data/lib/acts_as_taggable_on/acts_as_taggable_on/compatibility.rb +1 -1
  20. data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +24 -13
  21. data/lib/acts_as_taggable_on/engine.rb +6 -0
  22. data/lib/acts_as_taggable_on/tag.rb +27 -7
  23. data/lib/acts_as_taggable_on/taggable.rb +6 -6
  24. data/lib/acts_as_taggable_on/tagger.rb +6 -6
  25. data/lib/acts_as_taggable_on/tags_helper.rb +1 -1
  26. data/lib/acts_as_taggable_on/version.rb +1 -1
  27. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +4 -71
  28. data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +19 -19
  29. data/spec/acts_as_taggable_on/caching_spec.rb +77 -0
  30. data/spec/acts_as_taggable_on/tags_helper_spec.rb +10 -10
  31. data/spec/schema.rb +25 -21
  32. data/spec/spec_helper.rb +9 -25
  33. metadata +40 -56
  34. data/gemfiles/rails_4.gemfile +0 -8
  35. data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +0 -39
  36. data/spec/generators/acts_as_taggable_on/migration/migration_generator_spec.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d0b7cd2b4e279238a0fb8464721b40c3dbedaacd
4
- data.tar.gz: edd07332dcbd884be1daab9e65d9be28b6f3f695
3
+ metadata.gz: 5b46e80f19a5c7de71ec448bd0700ef672ea9639
4
+ data.tar.gz: d7c19bc3aec73a2b5d1ff08ad18cb9c85e61225c
5
5
  SHA512:
6
- metadata.gz: 65f468a535ce620033df88d152bd5e1bff722c01a197d233794da097e682b29ad5f4ebf46b4eb46a18957d2ecda9f6699aad27b42789a2c8ee8d7c4f68e985ba
7
- data.tar.gz: 2fd5249aa31f826fd56666dd3d07c4a63df1803722fc7e29c02b39fdbff6f0459316f30a1bb9345c53e885fa5a0edfd30495e211e8e6e90630600d9d60cd69a5
6
+ metadata.gz: 4ac4317c1fa00caa6f048d4958d830da83bae5a48d8fd2f4018918319069e9e0311b99318cfe337fcd8d23f9c37055484e1c40c1ab0ecda2c256d361315b0848
7
+ data.tar.gz: 7e29cf71dfce65f2ac65d0a10972c6b26344398278c53b088b9069ec728955e697389f496b25a8f57fd521b6349aaa2ef827caab78bf8a00c7416c9be43c21e5
@@ -1,9 +1,18 @@
1
- script: "cp spec/database.yml.sample spec/database.yml && bundle install && bundle exec rake"
2
1
  rvm:
3
- - 1.8.7
4
- - 1.9.2
5
2
  - 1.9.3
3
+ - 2.0.0
6
4
  env:
7
5
  - DB=sqlite3
8
6
  - DB=mysql
9
- - DB=postgresql
7
+ - DB=postgresql
8
+ gemfile:
9
+ - gemfiles/rails_3.2.gemfile
10
+ - gemfiles/rails_4.0.gemfile
11
+ - gemfiles/rails_4.1.gemfile
12
+ cache: bundler
13
+ script: bundle exec rake
14
+ before_install:
15
+ - gem install bundler
16
+ bundler_args: '--without local_development'
17
+ matrix:
18
+ fast_finish: true
data/Appraisals CHANGED
@@ -1,7 +1,11 @@
1
- appraise "rails-3" do
2
- gem "rails", "3.2.13"
1
+ appraise "rails-3.2" do
2
+ gem "rails", "~> 3.2"
3
3
  end
4
4
 
5
- appraise "rails-4" do
6
- gem "rails", "4.0.0.beta1"
5
+ appraise "rails-4.0" do
6
+ gem "rails", "~> 4.0"
7
+ end
8
+
9
+ appraise "rails-4.1" do
10
+ gem "rails", "~> 4.1.0.beta1"
7
11
  end
@@ -0,0 +1,47 @@
1
+ Changes are below categorized as `Features, Fixes, or Misc`.
2
+
3
+ Each change should fall into categories that would affect whether the release is major (breaking changes), minor (new behavior), or patch (bug fix). See [semver](http://semver.org/) and [pessimistic versioning](http://guides.rubygems.org/patterns/#pessimistic_version_constraint)
4
+
5
+ As such, a _Feature_ would map to either major or minor. A _bug fix_ to a patch. And _misc_ is either minor or patch, the difference being kind of fuzzy for the purposes of history. Adding tests would be patch level.
6
+
7
+ ### Master [changes](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.0.0...master)
8
+
9
+ * Breaking Changes
10
+ * Features
11
+ * Fixes
12
+ * Misc
13
+
14
+ ### [3.0.0 / 2014-01-01](https://github.com/mbleigh/acts-as-taggable-on/compare/v2.4.1...v3.0.0)
15
+
16
+ * Breaking Changes
17
+ * No longer supports Ruby 1.8.
18
+ * Features
19
+ * Supports Rails 4.1.
20
+ * Misc (TODO: expand)
21
+ * [zquest #359](https://github.com/mbleigh/acts-as-taggable-on/pull/359)
22
+ * [rsl #367](https://github.com/mbleigh/acts-as-taggable-on/pull/367)
23
+ * [ktdreyer #383](https://github.com/mbleigh/acts-as-taggable-on/pull/383)
24
+ * [cwoodcox #346](https://github.com/mbleigh/acts-as-taggable-on/pull/346)
25
+ * [mrb #421](https://github.com/mbleigh/acts-as-taggable-on/pull/421)
26
+ * [bf4 #430](https://github.com/mbleigh/acts-as-taggable-on/pull/430)
27
+ * [sanemat #368](https://github.com/mbleigh/acts-as-taggable-on/pull/368)
28
+ * [bf4 #343](https://github.com/mbleigh/acts-as-taggable-on/pull/343)
29
+ * [marclennox #429](https://github.com/mbleigh/acts-as-taggable-on/pull/429)
30
+ * [shekibobo #403](https://github.com/mbleigh/acts-as-taggable-on/pull/403)
31
+ * [ches ktdreyer #410](https://github.com/mbleigh/acts-as-taggable-on/pull/410)
32
+ * [makaroni4 #371](https://github.com/mbleigh/acts-as-taggable-on/pull/371)
33
+ * [kenzai dstosik awt #431](https://github.com/mbleigh/acts-as-taggable-on/pull/431)
34
+ * [bf4 joelcogen shekibobo aaronchi #438](https://github.com/mbleigh/acts-as-taggable-on/pull/438)
35
+ * [seuros #442](https://github.com/mbleigh/acts-as-taggable-on/pull/442)
36
+ * [bf4 #445](https://github.com/mbleigh/acts-as-taggable-on/pull/445)
37
+ * [eaglemt #446](https://github.com/mbleigh/acts-as-taggable-on/pull/446)
38
+
39
+ ### 3.0.0.rc2 [changes](https://github.com/mbleigh/acts-as-taggable-on/compare/fork-v3.0.0.rc1...fork-v3.0.0.rc2)
40
+
41
+ ### 3.0.0.rc1 [changes](https://github.com/mbleigh/acts-as-taggable-on/compare/v2.4.1...fork-v3.0.0.rc1)
42
+
43
+ ### [2.4.1 / 2013-05-07](https://github.com/mbleigh/acts-as-taggable-on/compare/v2.4.0...v2.4.1)
44
+
45
+ * Features
46
+ * Fixes
47
+ * Misc
data/Gemfile CHANGED
@@ -2,4 +2,10 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'appraisal'
5
+ group :local_development do
6
+ gem 'guard'
7
+ gem 'guard-rspec'
8
+ gem 'appraisal'
9
+ gem 'rake'
10
+ end
11
+
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # ActsAsTaggableOn
2
2
  [![Build Status](https://secure.travis-ci.org/mbleigh/acts-as-taggable-on.png)](http://travis-ci.org/mbleigh/acts-as-taggable-on)
3
+ [![Code Climate](https://codeclimate.com/github/mbleigh/acts-as-taggable-on.png)](https://codeclimate.com/github/mbleigh/acts-as-taggable-on)
3
4
 
4
5
  This plugin was originally based on Acts as Taggable on Steroids by Jonathan Viney.
5
6
  It has evolved substantially since that point, but all credit goes to him for the
@@ -20,7 +21,7 @@ Versions 2.x are compatible with Ruby 1.8.7+ and Rails 3.
20
21
 
21
22
  Versions 2.4.1 and up are compatible with Rails 4 too (thanks to arabonradar and cwoodcox).
22
23
 
23
- Versions 3.x (currently unreleased) are compatible with Ruby 1.9.3+ and Rails 3 and 4.
24
+ Versions 3.x (currently unreleased) are compatible with Ruby 1.9.3+ and Rails 3 and 4. There is a [release candidate you may try](http://rubygems.org/gems/acts_as_taggable_on).
24
25
 
25
26
  For an up-to-date roadmap, see https://github.com/mbleigh/acts-as-taggable-on/issues/milestones
26
27
 
@@ -41,21 +42,17 @@ bundle
41
42
  #### Post Installation
42
43
 
43
44
  ```shell
45
+ # For the latest versions
46
+ rake railties:install:migrations FROM=acts_as_taggable_on_engine db:migrate
47
+
48
+ # For versions 2.4.1 and earlier
44
49
  rails generate acts_as_taggable_on:migration
45
50
  rake db:migrate
46
51
  ```
47
52
 
48
- ## Testing
53
+ #### Upgrading
49
54
 
50
- Acts As Taggable On uses RSpec for its test coverage. Inside the gem
51
- directory, you can run the specs with:
52
-
53
- ```shell
54
- bundle
55
- rake spec
56
- ```
57
-
58
- If you want, add a `.ruby-version` file in the project root (and use rbenv or RVM) to work on a specific version of Ruby.
55
+ see [UPGRADING](UPGRADING)
59
56
 
60
57
  ## Usage
61
58
 
@@ -298,6 +295,19 @@ We have a long list of valued contributors. [Check them all](https://github.com/
298
295
 
299
296
  * [Joost Baaij](https://github.com/tilsammans)
300
297
 
298
+ ## Testing
299
+
300
+ Acts As Taggable On uses RSpec for its test coverage. Inside the gem
301
+ directory, you can run the specs with:
302
+
303
+ ```shell
304
+ bundle
305
+ rake spec
306
+ ```
307
+
308
+ You can run all the tests across all the Rails versions by running `rake appraise`. If you'd also like to [run the tests across all rubies and databases as configured for Travis CI, install and run `wwtd`](https://github.com/grosser/wwtd).
309
+
310
+
301
311
  ## License
302
312
 
303
313
  See [LICENSE](https://github.com/mbleigh/acts-as-taggable-on/blob/master/LICENSE.md)
data/Rakefile CHANGED
@@ -1,9 +1,27 @@
1
1
  require 'rubygems'
2
- require 'bundler/setup'
3
- require 'appraisal'
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ STDERR.puts "Bundler not loaded"
6
+ end
7
+
8
+ desc 'Copy sample spec database.yml over if not exists'
9
+ task :copy_db_config do
10
+ cp 'spec/database.yml.sample', 'spec/database.yml'
11
+ end
12
+
13
+ task :spec => [:copy_db_config]
4
14
 
5
15
  desc 'Default: run specs'
6
- task :default => :spec
16
+ task :default => :spec
17
+
18
+ begin
19
+ require 'appraisal'
20
+ desc 'Run tests across gemfiles specified in Appraisals'
21
+ task :appraise => ['appraisal:cleanup', 'appraisal:install', 'appraisal']
22
+ rescue LoadError
23
+ puts "appraisal tasks not available"
24
+ end
7
25
 
8
26
  require 'rspec/core/rake_task'
9
27
  RSpec::Core::RakeTask.new do |t|
@@ -0,0 +1,7 @@
1
+ When upgrading
2
+
3
+ Re-run the migrations generator
4
+
5
+ rake railties:install:migrations FROM=acts_as_taggable_on_engine db:migrate
6
+
7
+ It will create any new migrations and skip existing ones
@@ -24,12 +24,12 @@ Gem::Specification.new do |gem|
24
24
 
25
25
  gem.add_runtime_dependency 'rails', ['>= 3', '< 5']
26
26
 
27
- gem.add_development_dependency 'rspec-rails', '2.13.0' # 2.13.1 is broken
28
- gem.add_development_dependency 'rspec', '~> 2.6'
29
- gem.add_development_dependency 'ammeter'
30
27
  gem.add_development_dependency 'sqlite3'
31
28
  gem.add_development_dependency 'mysql2', '~> 0.3.7'
32
29
  gem.add_development_dependency 'pg'
33
- gem.add_development_dependency 'guard'
34
- gem.add_development_dependency 'guard-rspec'
30
+
31
+ gem.add_development_dependency 'rspec-rails', '2.13.0' # 2.13.1 is broken
32
+ gem.add_development_dependency 'rspec', '~> 2.6'
33
+ gem.add_development_dependency 'ammeter'
34
+
35
35
  end
@@ -0,0 +1,21 @@
1
+ class AddMissingUniqueIndices < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ add_index :tags, :name, unique: true
5
+
6
+ remove_index :taggings, :tag_id
7
+ remove_index :taggings, [:taggable_id, :taggable_type, :context]
8
+ add_index :taggings,
9
+ [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type],
10
+ unique: true, name: 'taggings_idx'
11
+ end
12
+
13
+ def self.down
14
+ remove_index :tags, :name
15
+
16
+ remove_index :taggings, name: 'tagging_idx'
17
+ add_index :taggings, :tag_id
18
+ add_index :taggings, [:taggable_id, :taggable_type, :context]
19
+ end
20
+
21
+ end
@@ -2,7 +2,6 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "appraisal"
6
- gem "rails", "3.2.13"
5
+ gem "rails", "~> 3.2"
7
6
 
8
7
  gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 4.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 4.1.0.beta1"
6
+
7
+ gemspec :path=>"../"
@@ -1,11 +1,11 @@
1
1
  require "active_record"
2
2
  require "active_record/version"
3
+ require "active_support/core_ext/module"
3
4
  require "action_view"
5
+ require 'active_support/all'
4
6
 
5
7
  require "digest/sha1"
6
8
 
7
- $LOAD_PATH.unshift(File.dirname(__FILE__))
8
-
9
9
  module ActsAsTaggableOn
10
10
  mattr_accessor :delimiter
11
11
  @@delimiter = ','
@@ -49,17 +49,13 @@ require "acts_as_taggable_on/tag"
49
49
  require "acts_as_taggable_on/tag_list"
50
50
  require "acts_as_taggable_on/tags_helper"
51
51
  require "acts_as_taggable_on/tagging"
52
+ require 'acts_as_taggable_on/engine'
52
53
 
53
- $LOAD_PATH.shift
54
-
55
-
56
- if defined?(ActiveRecord::Base)
57
- ActiveRecord::Base.extend ActsAsTaggableOn::Compatibility
58
- ActiveRecord::Base.extend ActsAsTaggableOn::Taggable
59
- ActiveRecord::Base.send :include, ActsAsTaggableOn::Tagger
54
+ ActiveSupport.on_load(:active_record) do
55
+ extend ActsAsTaggableOn::Compatibility
56
+ extend ActsAsTaggableOn::Taggable
57
+ include ActsAsTaggableOn::Tagger
60
58
  end
61
-
62
- if defined?(ActionView::Base)
63
- ActionView::Base.send :include, ActsAsTaggableOn::TagsHelper
59
+ ActiveSupport.on_load(:action_view) do
60
+ include ActsAsTaggableOn::TagsHelper
64
61
  end
65
-
@@ -0,0 +1,6 @@
1
+ $stderr.puts <<EOF
2
+ You are requiring 'acts_as_taggable_on' in the 'acts-as-taggable-on' gem.
3
+
4
+ Please change your require to 'acts-as-taggable-on'.
5
+ EOF
6
+ require_relative 'acts-as-taggable-on'
@@ -1,41 +1,69 @@
1
1
  module ActsAsTaggableOn::Taggable
2
2
  module Cache
3
3
  def self.included(base)
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
-
7
- base.send :include, ActsAsTaggableOn::Taggable::Cache::InstanceMethods
8
- base.extend ActsAsTaggableOn::Taggable::Cache::ClassMethods
9
-
10
- base.class_eval do
11
- before_save :save_cached_tag_list
4
+ # When included, conditionally adds tag caching methods when the model
5
+ # has any "cached_#{tag_type}_list" column
6
+ base.instance_eval do
7
+ # @private
8
+ def _has_tags_cache_columns?(db_columns)
9
+ db_column_names = db_columns.map(&:name)
10
+ tag_types.any? {|context|
11
+ db_column_names.include?("cached_#{context.to_s.singularize}_list")
12
+ }
13
+ end
14
+
15
+ # @private
16
+ def _add_tags_caching_methods
17
+ send :include, ActsAsTaggableOn::Taggable::Cache::InstanceMethods
18
+ extend ActsAsTaggableOn::Taggable::Cache::ClassMethods
19
+
20
+ before_save :save_cached_tag_list
21
+
22
+ initialize_tags_cache
23
+ end
24
+
25
+ # ActiveRecord::Base.columns makes a database connection and caches the calculated
26
+ # columns hash for the record as @columns. Since we don't want to add caching
27
+ # methods until we confirm the presence of a caching column, and we don't
28
+ # want to force opening a database connection when the class is loaded,
29
+ # here we intercept and cache the call to :columns as @acts_as_taggable_on_columns
30
+ # to mimic the underlying behavior. While processing this first call to columns,
31
+ # we do the caching column check and dynamically add the class and instance methods
32
+ def columns
33
+ @acts_as_taggable_on_columns ||= begin
34
+ db_columns = super
35
+ if _has_tags_cache_columns?(db_columns)
36
+ _add_tags_caching_methods
37
+ end
38
+ db_columns
39
+ end
40
+ end
41
+
12
42
  end
13
-
14
- base.initialize_acts_as_taggable_on_cache
15
43
  end
16
-
44
+
17
45
  module ClassMethods
18
- def initialize_acts_as_taggable_on_cache
46
+ def initialize_tags_cache
19
47
  tag_types.map(&:to_s).each do |tag_type|
20
48
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
21
49
  def self.caching_#{tag_type.singularize}_list?
22
50
  caching_tag_list_on?("#{tag_type}")
23
- end
51
+ end
24
52
  RUBY
25
- end
53
+ end
26
54
  end
27
-
55
+
28
56
  def acts_as_taggable_on(*args)
29
57
  super(*args)
30
- initialize_acts_as_taggable_on_cache
58
+ initialize_tags_cache
31
59
  end
32
-
60
+
33
61
  def caching_tag_list_on?(context)
34
62
  column_names.include?("cached_#{context.to_s.singularize}_list")
35
63
  end
36
64
  end
37
-
38
- module InstanceMethods
65
+
66
+ module InstanceMethods
39
67
  def save_cached_tag_list
40
68
  tag_types.map(&:to_s).each do |tag_type|
41
69
  if self.class.send("caching_#{tag_type.singularize}_list?")
@@ -45,9 +73,10 @@ module ActsAsTaggableOn::Taggable
45
73
  end
46
74
  end
47
75
  end
48
-
76
+
49
77
  true
50
78
  end
51
79
  end
80
+
52
81
  end
53
82
  end
@@ -5,7 +5,7 @@ module ActsAsTaggableOn::Taggable
5
5
  base.extend ActsAsTaggableOn::Taggable::Collection::ClassMethods
6
6
  base.initialize_acts_as_taggable_on_collection
7
7
  end
8
-
8
+
9
9
  module ClassMethods
10
10
  def initialize_acts_as_taggable_on_collection
11
11
  tag_types.map(&:to_s).each do |tag_type|
@@ -24,16 +24,16 @@ module ActsAsTaggableOn::Taggable
24
24
 
25
25
  def self.top_#{tag_type}(limit = 10)
26
26
  tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)
27
- end
27
+ end
28
28
  RUBY
29
- end
29
+ end
30
30
  end
31
-
31
+
32
32
  def acts_as_taggable_on(*args)
33
33
  super(*args)
34
34
  initialize_acts_as_taggable_on_collection
35
35
  end
36
-
36
+
37
37
  def tag_counts_on(context, options = {})
38
38
  all_tag_counts(options.merge({:on => context.to_s}))
39
39
  end
@@ -86,12 +86,13 @@ module ActsAsTaggableOn::Taggable
86
86
  group_columns = "#{ActsAsTaggableOn::Tagging.table_name}.tag_id"
87
87
 
88
88
  # Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
89
- ids = select("#{table_name}.#{primary_key}").map(&:id)
90
- tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(?)", ids).group(group_columns)
91
-
92
- 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")
89
+ scoped_select = "#{table_name}.#{primary_key}"
90
+ tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{safe_to_sql(select(scoped_select))})").group(group_columns)
91
+
92
+ tag_scope = tag_scope.joins("JOIN (#{safe_to_sql(tagging_scope)}) AS #{ActsAsTaggableOn::Tagging.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id")
93
+ tag_scope.extending(CalculationMethods)
93
94
  end
94
-
95
+
95
96
  ##
96
97
  # Calculate the tag counts for all tags.
97
98
  #
@@ -110,29 +111,29 @@ module ActsAsTaggableOn::Taggable
110
111
  scope = {}
111
112
 
112
113
  ## Generate conditions:
113
- options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]
114
+ options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]
114
115
 
115
116
  start_at_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
116
117
  end_at_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
117
-
118
+
118
119
  taggable_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.taggable_type = ?", base_class.name])
119
- taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = ?", options.delete(:id)]) if options[:id]
120
+ taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = ?", options[:id]]) if options[:id]
120
121
  taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", options.delete(:on).to_s]) if options[:on]
121
-
122
+
122
123
  tagging_conditions = [
123
124
  taggable_conditions,
124
125
  scope[:conditions],
125
126
  start_at_conditions,
126
127
  end_at_conditions
127
128
  ].compact.reverse
128
-
129
+
129
130
  tag_conditions = [
130
- options[:conditions]
131
+ options[:conditions]
131
132
  ].compact.reverse
132
-
133
+
133
134
  ## Generate joins:
134
135
  taggable_join = "INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id"
135
- 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
136
+ 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
136
137
 
137
138
  tagging_joins = [
138
139
  taggable_join,
@@ -144,10 +145,10 @@ module ActsAsTaggableOn::Taggable
144
145
 
145
146
  ## Generate scope:
146
147
  tagging_scope = ActsAsTaggableOn::Tagging.select("#{ActsAsTaggableOn::Tagging.table_name}.tag_id, COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) AS tags_count")
147
- tag_scope = ActsAsTaggableOn::Tag.select("#{ActsAsTaggableOn::Tag.table_name}.*, #{ActsAsTaggableOn::Tagging.table_name}.tags_count AS count").order(options[:order]).limit(options[:limit])
148
+ tag_scope = ActsAsTaggableOn::Tag.select("#{ActsAsTaggableOn::Tag.table_name}.*, #{ActsAsTaggableOn::Tagging.table_name}.tags_count AS count").order(options[:order]).limit(options[:limit])
148
149
 
149
150
  # Joins and conditions
150
- tagging_joins.each { |join| tagging_scope = tagging_scope.joins(join) }
151
+ tagging_joins.each { |join| tagging_scope = tagging_scope.joins(join) }
151
152
  tagging_conditions.each { |condition| tagging_scope = tagging_scope.where(condition) }
152
153
 
153
154
  tag_joins.each { |join| tag_scope = tag_scope.joins(join) }
@@ -156,29 +157,38 @@ module ActsAsTaggableOn::Taggable
156
157
  # GROUP BY and HAVING clauses:
157
158
  at_least = sanitize_sql(["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) >= ?", options.delete(:at_least)]) if options[:at_least]
158
159
  at_most = sanitize_sql(["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) <= ?", options.delete(:at_most)]) if options[:at_most]
159
- having = ["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) > 0", at_least, at_most].compact.join(' AND ')
160
+ having = ["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) > 0", at_least, at_most].compact.join(' AND ')
160
161
 
161
162
  group_columns = "#{ActsAsTaggableOn::Tagging.table_name}.tag_id"
162
163
 
163
- # Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
164
- scoped_select = "#{table_name}.#{primary_key}"
165
- select_query = "#{select(scoped_select).to_sql}"
166
-
167
- res = ActiveRecord::Base.connection.select_all(select_query).map { |item| item.values }.flatten.compact.join(",")
168
- res = "NULL" if res.blank?
164
+ unless options[:id]
165
+ # Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
166
+ scoped_select = "#{table_name}.#{primary_key}"
167
+ tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{safe_to_sql(select(scoped_select))})")
168
+ end
169
169
 
170
- tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{res})")
171
170
  tagging_scope = tagging_scope.group(group_columns).having(having)
172
171
 
173
- 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")
174
- tag_scope
172
+ tag_scope = tag_scope.joins("JOIN (#{safe_to_sql(tagging_scope)}) AS #{ActsAsTaggableOn::Tagging.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id")
173
+ tag_scope.extending(CalculationMethods)
174
+ end
175
+
176
+ def safe_to_sql(relation)
177
+ connection.respond_to?(:unprepared_statement) ? connection.unprepared_statement{relation.to_sql} : relation.to_sql
175
178
  end
176
179
  end
177
-
180
+
178
181
  module InstanceMethods
179
182
  def tag_counts_on(context, options={})
180
183
  self.class.tag_counts_on(context, options.merge(:id => id))
181
184
  end
182
185
  end
186
+
187
+ module CalculationMethods
188
+ def count
189
+ # https://github.com/rails/rails/commit/da9b5d4a8435b744fcf278fffd6d7f1e36d4a4f2
190
+ super(:all)
191
+ end
192
+ end
183
193
  end
184
- end
194
+ end