acts-as-taggable-on 2.2.0 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,13 +20,13 @@ was used.
20
20
 
21
21
  To use it, add it to your Gemfile:
22
22
 
23
- gem 'acts-as-taggable-on', '2.1.0'
23
+ gem 'acts-as-taggable-on', '~>2.1.0'
24
24
 
25
25
  === Rails 3.x
26
26
 
27
27
  To use it, add it to your Gemfile:
28
28
 
29
- gem 'acts-as-taggable-on'
29
+ gem 'acts-as-taggable-on', '~>2.2.0'
30
30
 
31
31
  ==== Post Installation
32
32
 
@@ -177,6 +177,14 @@ CSS:
177
177
  .css3 { font-size: 1.4em; }
178
178
  .css4 { font-size: 1.6em; }
179
179
 
180
+ == Remove unused tags
181
+
182
+ If you would like to remove unused tag objects after removing taggings, add
183
+
184
+ ActsAsTaggableOn::Tag.remove_unused = true
185
+
186
+ to initializer file.
187
+
180
188
  == Contributors
181
189
 
182
190
  We have a long list of valued contributors. {Check them all}[https://github.com/mbleigh/acts-as-taggable-on/contributors]
@@ -4,7 +4,7 @@ require 'acts-as-taggable-on/version'
4
4
  Gem::Specification.new do |gem|
5
5
  gem.name = %q{acts-as-taggable-on}
6
6
  gem.authors = ["Michael Bleigh"]
7
- gem.date = %q{2011-12-09}
7
+ gem.date = %q{2011-12-18}
8
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
9
  gem.summary = "Advanced tagging for Rails."
10
10
  gem.email = %q{michael@intridea.com}
@@ -2,18 +2,20 @@ require "active_record"
2
2
  require "active_record/version"
3
3
  require "action_view"
4
4
 
5
+ require "digest/sha1"
6
+
5
7
  $LOAD_PATH.unshift(File.dirname(__FILE__))
6
8
 
7
9
  require "acts_as_taggable_on/utils"
8
10
 
9
- require "acts_as_taggable_on/acts_as_taggable_on"
11
+ require "acts_as_taggable_on/taggable"
10
12
  require "acts_as_taggable_on/acts_as_taggable_on/core"
11
13
  require "acts_as_taggable_on/acts_as_taggable_on/collection"
12
14
  require "acts_as_taggable_on/acts_as_taggable_on/cache"
13
15
  require "acts_as_taggable_on/acts_as_taggable_on/ownership"
14
16
  require "acts_as_taggable_on/acts_as_taggable_on/related"
15
17
 
16
- require "acts_as_taggable_on/acts_as_tagger"
18
+ require "acts_as_taggable_on/tagger"
17
19
  require "acts_as_taggable_on/tag"
18
20
  require "acts_as_taggable_on/tag_list"
19
21
  require "acts_as_taggable_on/tags_helper"
@@ -1,4 +1,4 @@
1
1
  module ActsAsTaggableOn
2
- VERSION = '2.2.0'
2
+ VERSION = '2.2.1'
3
3
  end
4
4
 
@@ -53,11 +53,7 @@ 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]
@@ -92,8 +88,6 @@ module ActsAsTaggableOn::Taggable
92
88
  tag_joins = [
93
89
  ].compact
94
90
 
95
- [tagging_joins, tag_joins].each(&:reverse!) if ActiveRecord::VERSION::MAJOR < 3
96
-
97
91
  ## Generate scope:
98
92
  tagging_scope = ActsAsTaggableOn::Tagging.select("#{ActsAsTaggableOn::Tagging.table_name}.tag_id, COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) AS tags_count")
99
93
  tag_scope = ActsAsTaggableOn::Tag.select("#{ActsAsTaggableOn::Tag.table_name}.*, #{ActsAsTaggableOn::Tagging.table_name}.tags_count AS count").order(options[:order]).limit(options[:limit])
@@ -112,18 +106,12 @@ module ActsAsTaggableOn::Taggable
112
106
 
113
107
  group_columns = "#{ActsAsTaggableOn::Tagging.table_name}.tag_id"
114
108
 
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
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
+
127
115
 
128
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")
129
117
  tag_scope
@@ -93,8 +93,7 @@ module ActsAsTaggableOn::Taggable
93
93
  # avoid ambiguous column name
94
94
  taggings_context = context ? "_#{context}" : ''
95
95
 
96
- #TODO: fix alias to be smaller
97
- taggings_alias = "#{alias_base_name}#{taggings_context}_taggings_#{tags.map(&:safe_name).join('_')}_#{rand(1024)}"
96
+ taggings_alias = "#{alias_base_name[0..4]}#{taggings_context[0..6]}_taggings_#{sha_prefix(tags.map(&:safe_name).join('_'))}"
98
97
 
99
98
  tagging_join = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
100
99
  " ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
@@ -112,9 +111,8 @@ module ActsAsTaggableOn::Taggable
112
111
  return empty_result unless tags.length == tag_list.length
113
112
 
114
113
  tags.each do |tag|
115
- prefix = "#{tag.safe_name}_#{rand(1024)}"
116
114
 
117
- taggings_alias = "#{alias_base_name}_taggings_#{prefix}"
115
+ taggings_alias = "#{alias_base_name[0..11]}_taggings_#{sha_prefix(tag.safe_name)}"
118
116
 
119
117
  tagging_join = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
120
118
  " ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
@@ -60,7 +60,7 @@ module ActsAsTaggableOn::Taggable
60
60
 
61
61
  exclude_self = "#{klass.table_name}.#{klass.primary_key} != #{id} AND" if [self.class.base_class, self.class].include? klass
62
62
 
63
- group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(klass) : "#{klass.table_name}.#{klass.primary_key}"
63
+ group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(klass) : "#{klass.table_name}.#{klass.primary_key}"
64
64
 
65
65
  klass.scoped({ :select => "#{klass.table_name}.*, COUNT(#{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key}) AS count",
66
66
  :from => "#{klass.table_name}, #{ActsAsTaggableOn::Tag.table_name}, #{ActsAsTaggableOn::Tagging.table_name}",
@@ -2,6 +2,9 @@ module ActsAsTaggableOn
2
2
  class Tag < ::ActiveRecord::Base
3
3
  include ActsAsTaggableOn::Utils
4
4
 
5
+ cattr_accessor :remove_unused
6
+ self.remove_unused = false
7
+
5
8
  attr_accessible :name
6
9
 
7
10
  ### ASSOCIATIONS:
@@ -18,5 +18,17 @@ module ActsAsTaggableOn
18
18
  validates_presence_of :tag_id
19
19
 
20
20
  validates_uniqueness_of :tag_id, :scope => [ :taggable_type, :taggable_id, :context, :tagger_id, :tagger_type ]
21
+
22
+ after_destroy :remove_unused_tags
23
+
24
+ private
25
+
26
+ def remove_unused_tags
27
+ if Tag.remove_unused
28
+ if tag.taggings.count.zero?
29
+ tag.destroy
30
+ end
31
+ end
32
+ end
21
33
  end
22
34
  end
@@ -9,8 +9,8 @@ module ActsAsTaggableOn
9
9
  max_count = tags.sort_by(&:count).last.count.to_f
10
10
 
11
11
  tags.each do |tag|
12
- index = ((tag.count / max_count) * (classes.size - 1)).round
13
- yield tag, classes[index]
12
+ index = ((tag.count / max_count) * (classes.size - 1))
13
+ yield tag, classes[index.nan? ? 0 : index.round]
14
14
  end
15
15
  end
16
16
  end
@@ -15,6 +15,10 @@ module ActsAsTaggableOn
15
15
  ::ActiveRecord::Base.connection && ::ActiveRecord::Base.connection.adapter_name == 'SQLite'
16
16
  end
17
17
 
18
+ def sha_prefix(string)
19
+ Digest::SHA1.hexdigest(string + Time.now.to_s)[0..6]
20
+ end
21
+
18
22
  private
19
23
  def like_operator
20
24
  using_postgresql? ? 'ILIKE' : 'LIKE'
@@ -12,7 +12,9 @@ class ActsAsTaggableOnMigration < ActiveRecord::Migration
12
12
  t.references :taggable, :polymorphic => true
13
13
  t.references :tagger, :polymorphic => true
14
14
 
15
- t.string :context
15
+ # limit is created to prevent mysql error o index lenght for myisam table type.
16
+ # http://bit.ly/vgW2Ql
17
+ t.string :context, :limit => 128
16
18
 
17
19
  t.datetime :created_at
18
20
  end
@@ -74,20 +74,12 @@ describe ActsAsTaggableOn::Tag do
74
74
  it "should require a name" do
75
75
  @tag.valid?
76
76
 
77
- if ActiveRecord::VERSION::MAJOR >= 3
78
- @tag.errors[:name].should == ["can't be blank"]
79
- else
80
- @tag.errors[:name].should == "can't be blank"
81
- end
77
+ @tag.errors[:name].should == ["can't be blank"]
82
78
 
83
79
  @tag.name = "something"
84
80
  @tag.valid?
85
81
 
86
- if ActiveRecord::VERSION::MAJOR >= 3
87
- @tag.errors[:name].should == []
88
- else
89
- @tag.errors[:name].should be_nil
90
- end
82
+ @tag.errors[:name].should == []
91
83
  end
92
84
 
93
85
  it "should equal a tag with the same name" do
@@ -128,4 +120,35 @@ describe ActsAsTaggableOn::Tag do
128
120
  end
129
121
 
130
122
  end
123
+
124
+ describe ".remove_unused" do
125
+ before do
126
+ @taggable = TaggableModel.create(:name => "Bob Jones")
127
+ @tag = ActsAsTaggableOn::Tag.create(:name => "awesome")
128
+
129
+ @tagging = ActsAsTaggableOn::Tagging.create(:taggable => @taggable, :tag => @tag, :context => 'tags')
130
+ end
131
+
132
+ context "if set to true" do
133
+ before do
134
+ ActsAsTaggableOn::Tag.remove_unused = true
135
+ end
136
+
137
+ it "should remove unused tags after removing taggings" do
138
+ @tagging.destroy
139
+ ActsAsTaggableOn::Tag.find_by_name("awesome").should be_nil
140
+ end
141
+ end
142
+
143
+ context "if set to false" do
144
+ before do
145
+ ActsAsTaggableOn::Tag.remove_unused = false
146
+ end
147
+
148
+ it "should not remove unused tags after removing taggings" do
149
+ @tagging.destroy
150
+ ActsAsTaggableOn::Tag.find_by_name("awesome").should == @tag
151
+ end
152
+ end
153
+ end
131
154
  end
@@ -142,20 +142,9 @@ describe "Taggable" do
142
142
  TaggableModel.tagged_with(['rails, css'], :on => :needs, :any => true).tagged_with(['c++', 'java'], :on => :offerings, :any => true).to_a.should == [bob]
143
143
  end
144
144
 
145
- if ActiveRecord::VERSION::MAJOR >= 3
146
- it "should not return read-only records" do
147
- TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
148
- TaggableModel.tagged_with("ruby").first.should_not be_readonly
149
- end
150
- else
151
- xit "should not return read-only records" do
152
- # apparantly, there is no way to set readonly to false in a scope if joins are made
153
- end
154
-
155
- it "should be possible to return writable records" do
156
- TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
157
- TaggableModel.tagged_with("ruby").first(:readonly => false).should_not be_readonly
158
- end
145
+ it "should not return read-only records" do
146
+ TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
147
+ TaggableModel.tagged_with("ruby").first.should_not be_readonly
159
148
  end
160
149
 
161
150
  it "should be able to get scoped tag counts" do
@@ -13,11 +13,7 @@ describe ActsAsTaggableOn::Tagging do
13
13
 
14
14
  @tagging.should_not be_valid
15
15
 
16
- if ActiveRecord::VERSION::MAJOR >= 3
17
- @tagging.errors[:tag_id].should == ["can't be blank"]
18
- else
19
- @tagging.errors[:tag_id].should == "can't be blank"
20
- end
16
+ @tagging.errors[:tag_id].should == ["can't be blank"]
21
17
  end
22
18
 
23
19
  it "should not create duplicate taggings" do
@@ -28,4 +24,5 @@ describe ActsAsTaggableOn::Tagging do
28
24
  2.times { ActsAsTaggableOn::Tagging.create(:taggable => @taggable, :tag => @tag, :context => 'tags') }
29
25
  }.should change(ActsAsTaggableOn::Tagging, :count).by(1)
30
26
  end
27
+
31
28
  end
@@ -25,4 +25,20 @@ describe ActsAsTaggableOn::TagsHelper do
25
25
  tags["c++"].should == "sucky"
26
26
  tags["php"].should == "sucky"
27
27
  end
28
+
29
+ it "should handle tags with zero counts (build for empty)" do
30
+ bob = ActsAsTaggableOn::Tag.create(:name => "php")
31
+ tom = ActsAsTaggableOn::Tag.create(:name => "java")
32
+ eve = ActsAsTaggableOn::Tag.create(:name => "c++")
33
+
34
+ tags = { }
35
+
36
+ @helper.tag_cloud(ActsAsTaggableOn::Tag.all, ["sucky", "awesome"]) do |tag, css_class|
37
+ tags[tag.name] = css_class
38
+ end
39
+
40
+ tags["java"].should == "sucky"
41
+ tags["c++"].should == "sucky"
42
+ tags["php"].should == "sucky"
43
+ end
28
44
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts-as-taggable-on
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-09 00:00:00.000000000 Z
12
+ date: 2011-12-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &2153284680 !ruby/object:Gem::Requirement
16
+ requirement: &70149870225700 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.1'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2153284680
24
+ version_requirements: *70149870225700
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &2153284100 !ruby/object:Gem::Requirement
27
+ requirement: &70149870224800 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '2.5'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2153284100
35
+ version_requirements: *70149870224800
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: ammeter
38
- requirement: &2153283600 !ruby/object:Gem::Requirement
38
+ requirement: &70149870248200 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 0.1.3
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2153283600
46
+ version_requirements: *70149870248200
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: sqlite3
49
- requirement: &2153283220 !ruby/object:Gem::Requirement
49
+ requirement: &70149870247800 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2153283220
57
+ version_requirements: *70149870247800
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: mysql2
60
- requirement: &2153282280 !ruby/object:Gem::Requirement
60
+ requirement: &70149870247220 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 0.3.7
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2153282280
68
+ version_requirements: *70149870247220
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: pg
71
- requirement: &2153281780 !ruby/object:Gem::Requirement
71
+ requirement: &70149870246740 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *2153281780
79
+ version_requirements: *70149870246740
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: guard
82
- requirement: &2153281300 !ruby/object:Gem::Requirement
82
+ requirement: &70149870246180 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *2153281300
90
+ version_requirements: *70149870246180
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: guard-rspec
93
- requirement: &2153280680 !ruby/object:Gem::Requirement
93
+ requirement: &70149870245500 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *2153280680
101
+ version_requirements: *70149870245500
102
102
  description: With ActsAsTaggableOn, you can tag a single model on several contexts,
103
103
  such as skills, interests, and awards. It also provides other advanced functionality.
104
104
  email: michael@intridea.com
@@ -118,15 +118,15 @@ files:
118
118
  - acts-as-taggable-on.gemspec
119
119
  - lib/acts-as-taggable-on.rb
120
120
  - lib/acts-as-taggable-on/version.rb
121
- - lib/acts_as_taggable_on/acts_as_taggable_on.rb
122
121
  - lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb
123
122
  - lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb
124
123
  - lib/acts_as_taggable_on/acts_as_taggable_on/core.rb
125
124
  - lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb
126
125
  - lib/acts_as_taggable_on/acts_as_taggable_on/related.rb
127
- - lib/acts_as_taggable_on/acts_as_tagger.rb
128
126
  - lib/acts_as_taggable_on/tag.rb
129
127
  - lib/acts_as_taggable_on/tag_list.rb
128
+ - lib/acts_as_taggable_on/taggable.rb
129
+ - lib/acts_as_taggable_on/tagger.rb
130
130
  - lib/acts_as_taggable_on/tagging.rb
131
131
  - lib/acts_as_taggable_on/tags_helper.rb
132
132
  - lib/acts_as_taggable_on/utils.rb
@@ -163,7 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
163
163
  version: '0'
164
164
  segments:
165
165
  - 0
166
- hash: 2237132345428656164
166
+ hash: -2348258432577140293
167
167
  required_rubygems_version: !ruby/object:Gem::Requirement
168
168
  none: false
169
169
  requirements:
@@ -172,10 +172,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
172
172
  version: '0'
173
173
  segments:
174
174
  - 0
175
- hash: 2237132345428656164
175
+ hash: -2348258432577140293
176
176
  requirements: []
177
177
  rubyforge_project:
178
- rubygems_version: 1.8.11
178
+ rubygems_version: 1.8.10
179
179
  signing_key:
180
180
  specification_version: 3
181
181
  summary: Advanced tagging for Rails.