acts-as-taggable-on 1.0.6 → 1.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README +2 -4
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +58 -26
- data/lib/acts_as_taggable_on/tag_list.rb +2 -0
- data/spec/acts_as_taggable_on/tag_list_spec.rb +11 -0
- data/spec/acts_as_taggable_on/taggable_spec.rb +27 -0
- data/spec/spec.opts +0 -4
- data/spec/spec_helper.rb +1 -2
- metadata +2 -2
data/README
CHANGED
@@ -35,17 +35,15 @@ GemPlugin
|
|
35
35
|
Acts As Taggable On is also available as a gem plugin using Rails 2.1's gem dependencies.
|
36
36
|
To install the gem, add this to your config/environment.rb:
|
37
37
|
|
38
|
-
config.gem "
|
38
|
+
config.gem "acts-as-taggable-on", :source => "http://gemcutter.org"
|
39
39
|
|
40
40
|
After that, you can run "rake gems:install" to install the gem if you don't already have it.
|
41
|
-
See http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies for
|
42
|
-
additional details about gem dependencies in Rails.
|
43
41
|
|
44
42
|
** NOTE **
|
45
43
|
Some issues have been experienced with "rake gems:install". If that doesn't work to install the gem,
|
46
44
|
try just installing it as a normal gem:
|
47
45
|
|
48
|
-
gem install
|
46
|
+
gem install acts-as-taggable-on --source http://gemcutter.org
|
49
47
|
|
50
48
|
Post Installation (Rails)
|
51
49
|
-------------------------
|
data/Rakefile
CHANGED
@@ -11,6 +11,7 @@ begin
|
|
11
11
|
gemspec.authors = ["Michael Bleigh"]
|
12
12
|
gemspec.files = FileList["[A-Z]*", "{lib,spec,rails}/**/*"] - FileList["**/*.log"]
|
13
13
|
end
|
14
|
+
Jeweler::GemcutterTasks.new
|
14
15
|
rescue LoadError
|
15
16
|
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
16
17
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.7
|
@@ -68,6 +68,10 @@ module ActiveRecord
|
|
68
68
|
def top_#{tag_type}(limit = 10)
|
69
69
|
tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)
|
70
70
|
end
|
71
|
+
|
72
|
+
def self.top_#{tag_type}(limit = 10)
|
73
|
+
tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)
|
74
|
+
end
|
71
75
|
RUBY
|
72
76
|
end
|
73
77
|
|
@@ -87,8 +91,8 @@ module ActiveRecord
|
|
87
91
|
after_save :save_tags
|
88
92
|
|
89
93
|
if respond_to?(:named_scope)
|
90
|
-
named_scope :tagged_with, lambda{ |
|
91
|
-
find_options_for_find_tagged_with(
|
94
|
+
named_scope :tagged_with, lambda{ |*args|
|
95
|
+
find_options_for_find_tagged_with(*args)
|
92
96
|
}
|
93
97
|
end
|
94
98
|
end
|
@@ -126,36 +130,55 @@ module ActiveRecord
|
|
126
130
|
end
|
127
131
|
|
128
132
|
def find_options_for_find_tagged_with(tags, options = {})
|
129
|
-
tags =
|
130
|
-
|
133
|
+
tags = TagList.from(tags)
|
134
|
+
|
131
135
|
return {} if tags.empty?
|
132
|
-
|
136
|
+
|
137
|
+
joins = []
|
133
138
|
conditions = []
|
134
|
-
conditions << sanitize_sql(options.delete(:conditions)) if options[:conditions]
|
135
139
|
|
136
|
-
|
137
|
-
conditions << sanitize_sql(["context = ?",on.to_s])
|
138
|
-
end
|
139
|
-
|
140
|
-
taggings_alias, tags_alias = "#{table_name}_taggings", "#{table_name}_tags"
|
140
|
+
context = options.delete(:on)
|
141
141
|
|
142
|
+
|
142
143
|
if options.delete(:exclude)
|
143
|
-
tags_conditions = tags.map { |t| sanitize_sql(["#{Tag.table_name}.name LIKE ?", t]) }.join(" OR ")
|
144
|
-
conditions <<
|
145
|
-
|
146
|
-
|
144
|
+
tags_conditions = "(" + tags.map { |t| sanitize_sql(["#{Tag.table_name}.name LIKE ?", t]) }.join(" OR ") + ")"
|
145
|
+
conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{Tagging.table_name}.taggable_id FROM #{Tagging.table_name} JOIN #{Tag.table_name} ON #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND #{tags_conditions} WHERE #{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"
|
146
|
+
|
147
|
+
else
|
148
|
+
tags.each do |tag|
|
149
|
+
safe_tag = tag.gsub(/[^a-zA-Z0-9]/, '')
|
150
|
+
prefix = "#{safe_tag}_#{rand(1024)}"
|
151
|
+
|
152
|
+
taggings_alias = "#{table_name}_taggings_#{prefix}"
|
153
|
+
tags_alias = "#{table_name}_tags_#{prefix}"
|
154
|
+
|
155
|
+
tagging_join = "JOIN #{Tagging.table_name} #{taggings_alias}" +
|
156
|
+
" ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
|
157
|
+
" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"
|
158
|
+
tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context
|
159
|
+
|
160
|
+
tag_join = "JOIN #{Tag.table_name} #{tags_alias}" +
|
161
|
+
" ON #{tags_alias}.id = #{taggings_alias}.tag_id" +
|
162
|
+
" AND " + sanitize_sql(["#{tags_alias}.name like ?", tag])
|
163
|
+
|
164
|
+
joins << tagging_join
|
165
|
+
joins << tag_join
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
taggings_alias, tags_alias = "#{table_name}_taggings_group", "#{table_name}_tags_group"
|
147
170
|
|
148
|
-
|
149
|
-
|
150
|
-
|
171
|
+
if options.delete(:match_all)
|
172
|
+
joins << "LEFT OUTER JOIN #{Tagging.table_name} #{taggings_alias}" +
|
173
|
+
" ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
|
174
|
+
" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"
|
175
|
+
|
176
|
+
group = "#{table_name}.#{primary_key} HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
|
151
177
|
end
|
152
178
|
|
153
|
-
{ :
|
154
|
-
:
|
155
|
-
|
156
|
-
:conditions => conditions.join(" AND "),
|
157
|
-
:group => group
|
158
|
-
}.update(options)
|
179
|
+
{ :joins => joins.join(" "),
|
180
|
+
:group => group,
|
181
|
+
:conditions => conditions.join(" AND ") }.update(options)
|
159
182
|
end
|
160
183
|
|
161
184
|
# Calculate the tag counts for all tags.
|
@@ -178,6 +201,7 @@ module ActiveRecord
|
|
178
201
|
|
179
202
|
taggable_type = sanitize_sql(["#{Tagging.table_name}.taggable_type = ?", base_class.name])
|
180
203
|
taggable_id = sanitize_sql(["#{Tagging.table_name}.taggable_id = ?", options.delete(:id)]) if options[:id]
|
204
|
+
options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]
|
181
205
|
|
182
206
|
conditions = [
|
183
207
|
taggable_type,
|
@@ -192,7 +216,13 @@ module ActiveRecord
|
|
192
216
|
|
193
217
|
joins = ["LEFT OUTER JOIN #{Tagging.table_name} ON #{Tag.table_name}.id = #{Tagging.table_name}.tag_id"]
|
194
218
|
joins << sanitize_sql(["AND #{Tagging.table_name}.context = ?",options.delete(:on).to_s]) unless options[:on].nil?
|
195
|
-
|
219
|
+
|
220
|
+
joins << " INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{Tagging.table_name}.taggable_id"
|
221
|
+
unless self.descends_from_active_record?
|
222
|
+
# Current model is STI descendant, so add type checking to the join condition
|
223
|
+
joins << " AND #{table_name}.#{self.inheritance_column} = '#{self.name}'"
|
224
|
+
end
|
225
|
+
|
196
226
|
joins << scope[:joins] if scope && scope[:joins]
|
197
227
|
|
198
228
|
at_least = sanitize_sql(['COUNT(*) >= ?', options.delete(:at_least)]) if options[:at_least]
|
@@ -204,7 +234,9 @@ module ActiveRecord
|
|
204
234
|
{ :select => "#{Tag.table_name}.id, #{Tag.table_name}.name, COUNT(*) AS count",
|
205
235
|
:joins => joins.join(" "),
|
206
236
|
:conditions => conditions,
|
207
|
-
:group => group_by
|
237
|
+
:group => group_by,
|
238
|
+
:limit => options[:limit],
|
239
|
+
:order => options[:order]
|
208
240
|
}
|
209
241
|
end
|
210
242
|
|
@@ -20,6 +20,12 @@ describe TagList do
|
|
20
20
|
@tag_list.include?("wicked").should be_true
|
21
21
|
end
|
22
22
|
|
23
|
+
it "should be able to add an array of words" do
|
24
|
+
@tag_list.add(["cool", "wicked"], :parse => true)
|
25
|
+
@tag_list.include?("cool").should be_true
|
26
|
+
@tag_list.include?("wicked").should be_true
|
27
|
+
end
|
28
|
+
|
23
29
|
it "should be able to remove words" do
|
24
30
|
@tag_list.remove("awesome")
|
25
31
|
@tag_list.include?("awesome").should be_false
|
@@ -30,6 +36,11 @@ describe TagList do
|
|
30
36
|
@tag_list.should be_empty
|
31
37
|
end
|
32
38
|
|
39
|
+
it "should be able to remove an array of words" do
|
40
|
+
@tag_list.remove(["awesome", "radical"], :parse => true)
|
41
|
+
@tag_list.should be_empty
|
42
|
+
end
|
43
|
+
|
33
44
|
it "should give a delimited list of words when converted to string" do
|
34
45
|
@tag_list.to_s.should == "awesome, radical"
|
35
46
|
end
|
@@ -117,6 +117,22 @@ describe "Taggable" do
|
|
117
117
|
TaggableModel.tagged_with('rails', :on => :skills).tagged_with('happier', :on => :tags).should == [bob]
|
118
118
|
end
|
119
119
|
|
120
|
+
it "should be able to find tagged with only the matching tags" do
|
121
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "lazy, happier")
|
122
|
+
frank = TaggableModel.create(:name => "Frank", :tag_list => "fitter, happier, inefficient")
|
123
|
+
steve = TaggableModel.create(:name => 'Steve', :tag_list => "fitter, happier")
|
124
|
+
|
125
|
+
TaggableModel.find_tagged_with("fitter, happier", :match_all => true).should == [steve]
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should be able to find tagged with some excluded tags" do
|
129
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "happier, lazy")
|
130
|
+
frank = TaggableModel.create(:name => "Frank", :tag_list => "happier")
|
131
|
+
steve = TaggableModel.create(:name => 'Steve', :tag_list => "happier")
|
132
|
+
|
133
|
+
TaggableModel.find_tagged_with("lazy", :exclude => true).should == [frank, steve]
|
134
|
+
end
|
135
|
+
|
120
136
|
describe "Single Table Inheritance" do
|
121
137
|
before do
|
122
138
|
[TaggableModel, Tag, Tagging, TaggableUser].each(&:delete_all)
|
@@ -143,5 +159,16 @@ describe "Taggable" do
|
|
143
159
|
InheritingTaggableModel.find_tagged_with("fork", :on => :parts).should be_empty
|
144
160
|
AlteredInheritingTaggableModel.find_tagged_with("fork", :on => :parts).first.should == @inherited_different
|
145
161
|
end
|
162
|
+
|
163
|
+
it "should have different tag_counts_on for inherited models" do
|
164
|
+
@inherited_same.tag_list = "bob, kelso"
|
165
|
+
@inherited_same.save!
|
166
|
+
@inherited_different.tag_list = "fork, spoon"
|
167
|
+
@inherited_different.save!
|
168
|
+
|
169
|
+
InheritingTaggableModel.tag_counts_on(:tags).map(&:name).should == %w(bob kelso)
|
170
|
+
AlteredInheritingTaggableModel.tag_counts_on(:tags).map(&:name).should == %w(fork spoon)
|
171
|
+
TaggableModel.tag_counts_on(:tags).map(&:name).should == %w(bob kelso fork spoon)
|
172
|
+
end
|
146
173
|
end
|
147
174
|
end
|
data/spec/spec.opts
CHANGED
data/spec/spec_helper.rb
CHANGED
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: 1.0.
|
4
|
+
version: 1.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Bleigh
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-11-12 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|