acts-as-taggable-on 1.0.6 → 1.0.7
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/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
|
|