acts-as-taggable-on 2.4.1 → 3.0.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.
- checksums.yaml +4 -4
- data/.travis.yml +13 -4
- data/Appraisals +8 -4
- data/CHANGELOG.md +47 -0
- data/Gemfile +7 -1
- data/README.md +21 -11
- data/Rakefile +21 -3
- data/UPGRADING +7 -0
- data/acts-as-taggable-on.gemspec +5 -5
- data/{lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb → db/migrate/1_acts_as_taggable_on_migration.rb} +0 -0
- data/db/migrate/2_add_missing_unique_indices.rb +21 -0
- data/gemfiles/{rails_3.gemfile → rails_3.2.gemfile} +1 -2
- data/gemfiles/rails_4.0.gemfile +7 -0
- data/gemfiles/rails_4.1.gemfile +7 -0
- data/lib/acts-as-taggable-on.rb +9 -13
- data/lib/acts_as_taggable_on.rb +6 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +49 -20
- data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +42 -32
- data/lib/acts_as_taggable_on/acts_as_taggable_on/compatibility.rb +1 -1
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +24 -13
- data/lib/acts_as_taggable_on/engine.rb +6 -0
- data/lib/acts_as_taggable_on/tag.rb +27 -7
- data/lib/acts_as_taggable_on/taggable.rb +6 -6
- data/lib/acts_as_taggable_on/tagger.rb +6 -6
- data/lib/acts_as_taggable_on/tags_helper.rb +1 -1
- data/lib/acts_as_taggable_on/version.rb +1 -1
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +4 -71
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +19 -19
- data/spec/acts_as_taggable_on/caching_spec.rb +77 -0
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +10 -10
- data/spec/schema.rb +25 -21
- data/spec/spec_helper.rb +9 -25
- metadata +40 -56
- data/gemfiles/rails_4.gemfile +0 -8
- data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +0 -39
- data/spec/generators/acts_as_taggable_on/migration/migration_generator_spec.rb +0 -22
@@ -104,14 +104,14 @@ module ActsAsTaggableOn::Taggable
|
|
104
104
|
tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{like_operator} ?", t]) }.join(" OR ")
|
105
105
|
end
|
106
106
|
|
107
|
-
conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"
|
107
|
+
conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name, nil)})"
|
108
108
|
|
109
109
|
if owned_by
|
110
110
|
joins << "JOIN #{ActsAsTaggableOn::Tagging.table_name}" +
|
111
111
|
" ON #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
|
112
|
-
" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)}" +
|
113
|
-
" AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = #{owned_by.id}" +
|
114
|
-
" AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = #{quote_value(owned_by.class.base_class.to_s)}"
|
112
|
+
" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name, nil)}" +
|
113
|
+
" AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = #{quote_value(owned_by.id, nil)}" +
|
114
|
+
" AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = #{quote_value(owned_by.class.base_class.to_s, nil)}"
|
115
115
|
end
|
116
116
|
|
117
117
|
elsif options.delete(:any)
|
@@ -134,11 +134,11 @@ module ActsAsTaggableOn::Taggable
|
|
134
134
|
|
135
135
|
tagging_join = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
|
136
136
|
" ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
|
137
|
-
" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"
|
137
|
+
" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name, nil)}"
|
138
138
|
tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context
|
139
139
|
|
140
140
|
# don't need to sanitize sql, map all ids and join with OR logic
|
141
|
-
conditions << tags.map { |t| "#{taggings_alias}.tag_id = #{t.id}" }.join(" OR ")
|
141
|
+
conditions << tags.map { |t| "#{taggings_alias}.tag_id = #{quote_value(t.id, nil)}" }.join(" OR ")
|
142
142
|
select_clause = "DISTINCT #{table_name}.*" unless context and tag_types.one?
|
143
143
|
|
144
144
|
if owned_by
|
@@ -160,8 +160,8 @@ module ActsAsTaggableOn::Taggable
|
|
160
160
|
taggings_alias = adjust_taggings_alias("#{alias_base_name[0..11]}_taggings_#{sha_prefix(tag.name)}")
|
161
161
|
tagging_join = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
|
162
162
|
" ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
|
163
|
-
" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}" +
|
164
|
-
" AND #{taggings_alias}.tag_id = #{tag.id}"
|
163
|
+
" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name, nil)}" +
|
164
|
+
" AND #{taggings_alias}.tag_id = #{quote_value(tag.id, nil)}"
|
165
165
|
|
166
166
|
tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context
|
167
167
|
|
@@ -183,7 +183,7 @@ module ActsAsTaggableOn::Taggable
|
|
183
183
|
if options.delete(:match_all)
|
184
184
|
joins << "LEFT OUTER JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
|
185
185
|
" ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
|
186
|
-
" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"
|
186
|
+
" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name, nil)}"
|
187
187
|
|
188
188
|
|
189
189
|
group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}"
|
@@ -245,8 +245,13 @@ module ActsAsTaggableOn::Taggable
|
|
245
245
|
|
246
246
|
def tag_list_cache_on(context)
|
247
247
|
variable_name = "@#{context.to_s.singularize}_list"
|
248
|
-
|
249
|
-
|
248
|
+
if instance_variable_get(variable_name)
|
249
|
+
instance_variable_get(variable_name)
|
250
|
+
elsif cached_tag_list_on(context) && self.class.caching_tag_list_on?(context)
|
251
|
+
instance_variable_set(variable_name, ActsAsTaggableOn::TagList.from(cached_tag_list_on(context)))
|
252
|
+
else
|
253
|
+
instance_variable_set(variable_name, ActsAsTaggableOn::TagList.new(tags_on(context).map(&:name)))
|
254
|
+
end
|
250
255
|
end
|
251
256
|
|
252
257
|
def tag_list_on(context)
|
@@ -324,6 +329,12 @@ module ActsAsTaggableOn::Taggable
|
|
324
329
|
super(*args)
|
325
330
|
end
|
326
331
|
|
332
|
+
##
|
333
|
+
# Find existing tags or create non-existing tags
|
334
|
+
def load_tags(tag_list)
|
335
|
+
ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name(tag_list)
|
336
|
+
end
|
337
|
+
|
327
338
|
def save_tags
|
328
339
|
tagging_contexts.each do |context|
|
329
340
|
next unless tag_list_cache_set_on(context)
|
@@ -331,7 +342,7 @@ module ActsAsTaggableOn::Taggable
|
|
331
342
|
tag_list = tag_list_cache_on(context).uniq
|
332
343
|
|
333
344
|
# Find existing tags or create non-existing tags:
|
334
|
-
tags =
|
345
|
+
tags = load_tags(tag_list)
|
335
346
|
|
336
347
|
# Tag objects for currently assigned tags
|
337
348
|
current_tags = tags_on(context)
|
@@ -350,7 +361,7 @@ module ActsAsTaggableOn::Taggable
|
|
350
361
|
new_tags |= current_tags[index...current_tags.size] & shared_tags
|
351
362
|
|
352
363
|
# Order the array of tag objects to match the tag list
|
353
|
-
new_tags = tags.map do |t|
|
364
|
+
new_tags = tags.map do |t|
|
354
365
|
new_tags.find { |n| n.name.downcase == t.name.downcase }
|
355
366
|
end.compact
|
356
367
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
module ActsAsTaggableOn
|
2
3
|
class Tag < ::ActiveRecord::Base
|
3
4
|
include ActsAsTaggableOn::Utils
|
@@ -31,18 +32,29 @@ module ActsAsTaggableOn
|
|
31
32
|
|
32
33
|
def self.named_any(list)
|
33
34
|
if ActsAsTaggableOn.strict_case_match
|
34
|
-
|
35
|
+
clause = list.map { |tag|
|
36
|
+
sanitize_sql(["name = #{binary}?", as_8bit_ascii(tag)])
|
37
|
+
}.join(" OR ")
|
38
|
+
where(clause)
|
35
39
|
else
|
36
|
-
|
40
|
+
clause = list.map { |tag|
|
41
|
+
lowercase_ascii_tag = as_8bit_ascii(tag).downcase
|
42
|
+
sanitize_sql(["lower(name) = ?", lowercase_ascii_tag])
|
43
|
+
}.join(" OR ")
|
44
|
+
where(clause)
|
37
45
|
end
|
38
46
|
end
|
39
47
|
|
40
48
|
def self.named_like(name)
|
41
|
-
|
49
|
+
clause = ["name #{like_operator} ? ESCAPE '!'", "%#{escape_like(name)}%"]
|
50
|
+
where(clause)
|
42
51
|
end
|
43
52
|
|
44
53
|
def self.named_like_any(list)
|
45
|
-
|
54
|
+
clause = list.map { |tag|
|
55
|
+
sanitize_sql(["name #{like_operator} ? ESCAPE '!'", "%#{escape_like(tag.to_s)}%"])
|
56
|
+
}.join(" OR ")
|
57
|
+
where(clause)
|
46
58
|
end
|
47
59
|
|
48
60
|
### CLASS METHODS:
|
@@ -56,7 +68,7 @@ module ActsAsTaggableOn
|
|
56
68
|
end
|
57
69
|
|
58
70
|
def self.find_or_create_all_with_like_by_name(*list)
|
59
|
-
list =
|
71
|
+
list = Array(list).flatten
|
60
72
|
|
61
73
|
return [] if list.empty?
|
62
74
|
|
@@ -64,7 +76,7 @@ module ActsAsTaggableOn
|
|
64
76
|
|
65
77
|
list.map do |tag_name|
|
66
78
|
comparable_tag_name = comparable_name(tag_name)
|
67
|
-
existing_tag = existing_tags.
|
79
|
+
existing_tag = existing_tags.detect { |tag| comparable_name(tag.name) == comparable_tag_name }
|
68
80
|
|
69
81
|
existing_tag || Tag.create(:name => tag_name)
|
70
82
|
end
|
@@ -88,12 +100,20 @@ module ActsAsTaggableOn
|
|
88
100
|
private
|
89
101
|
|
90
102
|
def comparable_name(str)
|
91
|
-
str.
|
103
|
+
as_8bit_ascii(str).downcase
|
92
104
|
end
|
93
105
|
|
94
106
|
def binary
|
95
107
|
/mysql/ === ActiveRecord::Base.connection_config[:adapter] ? "BINARY " : nil
|
96
108
|
end
|
109
|
+
|
110
|
+
def as_8bit_ascii(string)
|
111
|
+
if defined?(Encoding)
|
112
|
+
string.to_s.force_encoding('BINARY')
|
113
|
+
else
|
114
|
+
string.to_s.mb_chars
|
115
|
+
end
|
116
|
+
end
|
97
117
|
end
|
98
118
|
end
|
99
119
|
end
|
@@ -25,7 +25,7 @@ module ActsAsTaggableOn
|
|
25
25
|
def acts_as_ordered_taggable
|
26
26
|
acts_as_ordered_taggable_on :tags
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
##
|
30
30
|
# Make a model taggable on specified contexts.
|
31
31
|
#
|
@@ -38,8 +38,8 @@ module ActsAsTaggableOn
|
|
38
38
|
def acts_as_taggable_on(*tag_types)
|
39
39
|
taggable_on(false, tag_types)
|
40
40
|
end
|
41
|
-
|
42
|
-
|
41
|
+
|
42
|
+
|
43
43
|
##
|
44
44
|
# Make a model taggable on specified contexts
|
45
45
|
# and preserves the order in which tags are created
|
@@ -53,9 +53,9 @@ module ActsAsTaggableOn
|
|
53
53
|
def acts_as_ordered_taggable_on(*tag_types)
|
54
54
|
taggable_on(true, tag_types)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
private
|
58
|
-
|
58
|
+
|
59
59
|
# Make a model taggable on specified contexts
|
60
60
|
# and optionally preserves the order in which tags are created
|
61
61
|
#
|
@@ -78,7 +78,7 @@ module ActsAsTaggableOn
|
|
78
78
|
self.tag_types = tag_types
|
79
79
|
class_attribute :preserve_tag_order
|
80
80
|
self.preserve_tag_order = preserve_tag_order
|
81
|
-
|
81
|
+
|
82
82
|
class_eval do
|
83
83
|
has_many :taggings, :as => :taggable, :dependent => :destroy, :class_name => "ActsAsTaggableOn::Tagging"
|
84
84
|
has_many :base_tags, :through => :taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag"
|
@@ -15,17 +15,17 @@ module ActsAsTaggableOn
|
|
15
15
|
# end
|
16
16
|
def acts_as_tagger(opts={})
|
17
17
|
class_eval do
|
18
|
-
has_many_with_compatibility :owned_taggings,
|
18
|
+
has_many_with_compatibility :owned_taggings,
|
19
19
|
opts.merge(
|
20
|
-
:as => :tagger,
|
20
|
+
:as => :tagger,
|
21
21
|
:dependent => :destroy,
|
22
22
|
:class_name => "ActsAsTaggableOn::Tagging"
|
23
23
|
)
|
24
24
|
|
25
|
-
has_many_with_compatibility :owned_tags,
|
26
|
-
:through => :owned_taggings,
|
27
|
-
:source => :tag,
|
28
|
-
:class_name => "ActsAsTaggableOn::Tag",
|
25
|
+
has_many_with_compatibility :owned_tags,
|
26
|
+
:through => :owned_taggings,
|
27
|
+
:source => :tag,
|
28
|
+
:class_name => "ActsAsTaggableOn::Tag",
|
29
29
|
:uniq => true
|
30
30
|
end
|
31
31
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
require 'spec_helper'
|
2
3
|
|
3
4
|
describe "Acts As Taggable On" do
|
@@ -8,7 +9,7 @@ describe "Acts As Taggable On" do
|
|
8
9
|
it "should provide a class method 'taggable?' that is false for untaggable models" do
|
9
10
|
UntaggableModel.should_not be_taggable
|
10
11
|
end
|
11
|
-
|
12
|
+
|
12
13
|
describe "Taggable Method Generation To Preserve Order" do
|
13
14
|
before(:each) do
|
14
15
|
clean_database!
|
@@ -46,7 +47,7 @@ describe "Acts As Taggable On" do
|
|
46
47
|
it "should have all tag types" do
|
47
48
|
@taggable.tag_types.should == [:tags, :languages, :skills, :needs, :offerings]
|
48
49
|
end
|
49
|
-
|
50
|
+
|
50
51
|
it "should create a class attribute for preserve tag order" do
|
51
52
|
@taggable.class.should respond_to(:preserve_tag_order?)
|
52
53
|
end
|
@@ -54,7 +55,7 @@ describe "Acts As Taggable On" do
|
|
54
55
|
it "should create an instance attribute for preserve tag order" do
|
55
56
|
@taggable.should respond_to(:preserve_tag_order?)
|
56
57
|
end
|
57
|
-
|
58
|
+
|
58
59
|
it "should respond 'false' to preserve_tag_order?" do
|
59
60
|
@taggable.class.preserve_tag_order?.should be_false
|
60
61
|
end
|
@@ -168,74 +169,6 @@ describe "Acts As Taggable On" do
|
|
168
169
|
end
|
169
170
|
end
|
170
171
|
|
171
|
-
describe 'Caching' do
|
172
|
-
before(:each) do
|
173
|
-
@taggable = CachedModel.new(:name => "Bob Jones")
|
174
|
-
@another_taggable = OtherCachedModel.new(:name => "John Smith")
|
175
|
-
end
|
176
|
-
|
177
|
-
it "should add saving of tag lists and cached tag lists to the instance" do
|
178
|
-
@taggable.should respond_to(:save_cached_tag_list)
|
179
|
-
@another_taggable.should respond_to(:save_cached_tag_list)
|
180
|
-
|
181
|
-
@taggable.should respond_to(:save_tags)
|
182
|
-
end
|
183
|
-
|
184
|
-
it "should add cached tag lists to the instance if cached column is not present" do
|
185
|
-
TaggableModel.new(:name => "Art Kram").should_not respond_to(:save_cached_tag_list)
|
186
|
-
end
|
187
|
-
|
188
|
-
it "should generate a cached column checker for each tag type" do
|
189
|
-
CachedModel.should respond_to(:caching_tag_list?)
|
190
|
-
OtherCachedModel.should respond_to(:caching_language_list?)
|
191
|
-
end
|
192
|
-
|
193
|
-
it 'should not have cached tags' do
|
194
|
-
@taggable.cached_tag_list.should be_blank
|
195
|
-
@another_taggable.cached_language_list.should be_blank
|
196
|
-
end
|
197
|
-
|
198
|
-
it 'should cache tags' do
|
199
|
-
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
200
|
-
@taggable.cached_tag_list.should == 'awesome, epic'
|
201
|
-
|
202
|
-
@another_taggable.update_attributes(:language_list => 'ruby, .net')
|
203
|
-
@another_taggable.cached_language_list.should == 'ruby, .net'
|
204
|
-
end
|
205
|
-
|
206
|
-
it 'should keep the cache' do
|
207
|
-
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
208
|
-
@taggable = CachedModel.find(@taggable)
|
209
|
-
@taggable.save!
|
210
|
-
@taggable.cached_tag_list.should == 'awesome, epic'
|
211
|
-
end
|
212
|
-
|
213
|
-
it 'should update the cache' do
|
214
|
-
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
215
|
-
@taggable.update_attributes(:tag_list => 'awesome')
|
216
|
-
@taggable.cached_tag_list.should == 'awesome'
|
217
|
-
end
|
218
|
-
|
219
|
-
it 'should remove the cache' do
|
220
|
-
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
221
|
-
@taggable.update_attributes(:tag_list => '')
|
222
|
-
@taggable.cached_tag_list.should be_blank
|
223
|
-
end
|
224
|
-
|
225
|
-
it 'should have a tag list' do
|
226
|
-
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
227
|
-
@taggable = CachedModel.find(@taggable.id)
|
228
|
-
@taggable.tag_list.sort.should == %w(awesome epic).sort
|
229
|
-
end
|
230
|
-
|
231
|
-
it 'should keep the tag list' do
|
232
|
-
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
233
|
-
@taggable = CachedModel.find(@taggable.id)
|
234
|
-
@taggable.save!
|
235
|
-
@taggable.tag_list.sort.should == %w(awesome epic).sort
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
172
|
context 'when tagging context ends in an "s" when singular (ex. "status", "glass", etc.)' do
|
240
173
|
describe 'caching' do
|
241
174
|
before { @taggable = OtherCachedModel.new(:name => "John Smith") }
|
@@ -4,7 +4,7 @@ describe "acts_as_tagger" do
|
|
4
4
|
before(:each) do
|
5
5
|
clean_database!
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
describe "Tagger Method Generation" do
|
9
9
|
before(:each) do
|
10
10
|
@tagger = User.new
|
@@ -13,55 +13,55 @@ describe "acts_as_tagger" do
|
|
13
13
|
it "should add #is_tagger? query method to the class-side" do
|
14
14
|
User.should respond_to(:is_tagger?)
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it "should return true from the class-side #is_tagger?" do
|
18
18
|
User.is_tagger?.should be_true
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
it "should return false from the base #is_tagger?" do
|
22
22
|
ActiveRecord::Base.is_tagger?.should be_false
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
it "should add #is_tagger? query method to the singleton" do
|
26
26
|
@tagger.should respond_to(:is_tagger?)
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
it "should add #tag method on the instance-side" do
|
30
30
|
@tagger.should respond_to(:tag)
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
it "should generate an association for #owned_taggings and #owned_tags" do
|
34
34
|
@tagger.should respond_to(:owned_taggings, :owned_tags)
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
describe "#tag" do
|
39
39
|
context 'when called with a non-existent tag context' do
|
40
40
|
before(:each) do
|
41
41
|
@tagger = User.new
|
42
42
|
@taggable = TaggableModel.new(:name=>"Richard Prior")
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
it "should by default not throw an exception " do
|
46
46
|
@taggable.tag_list_on(:foo).should be_empty
|
47
47
|
lambda {
|
48
48
|
@tagger.tag(@taggable, :with=>'this, and, that', :on=>:foo)
|
49
49
|
}.should_not raise_error
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
it 'should by default create the tag context on-the-fly' do
|
53
53
|
@taggable.tag_list_on(:here_ond_now).should be_empty
|
54
54
|
@tagger.tag(@taggable, :with=>'that', :on => :here_ond_now)
|
55
55
|
@taggable.tag_list_on(:here_ond_now).should_not include('that')
|
56
56
|
@taggable.all_tags_list_on(:here_ond_now).should include('that')
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
it "should show all the tag list when both public and owned tags exist" do
|
60
60
|
@taggable.tag_list = 'ruby, python'
|
61
61
|
@tagger.tag(@taggable, :with => 'java, lisp', :on => :tags)
|
62
62
|
@taggable.all_tags_on(:tags).map(&:name).sort.should == %w(ruby python java lisp).sort
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
it "should not add owned tags to the common list" do
|
66
66
|
@taggable.tag_list = 'ruby, python'
|
67
67
|
@tagger.tag(@taggable, :with => 'java, lisp', :on => :tags)
|
@@ -69,12 +69,12 @@ describe "acts_as_tagger" do
|
|
69
69
|
@tagger.tag(@taggable, :with => '', :on => :tags)
|
70
70
|
@taggable.tag_list.should == %w(ruby python)
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
it "should throw an exception when the default is over-ridden" do
|
74
74
|
@taggable.tag_list_on(:foo_boo).should be_empty
|
75
75
|
lambda {
|
76
76
|
@tagger.tag(@taggable, :with=>'this, and, that', :on=>:foo_boo, :force=>false)
|
77
|
-
}.should raise_error
|
77
|
+
}.should raise_error
|
78
78
|
end
|
79
79
|
|
80
80
|
it "should not create the tag context on-the-fly when the default is over-ridden" do
|
@@ -83,28 +83,28 @@ describe "acts_as_tagger" do
|
|
83
83
|
@taggable.tag_list_on(:foo_boo).should be_empty
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
describe "when called by multiple tagger's" do
|
88
88
|
before(:each) do
|
89
89
|
@user_x = User.create(:name => "User X")
|
90
90
|
@user_y = User.create(:name => "User Y")
|
91
91
|
@taggable = TaggableModel.create(:name => 'acts_as_taggable_on', :tag_list => 'plugin')
|
92
|
-
|
92
|
+
|
93
93
|
@user_x.tag(@taggable, :with => 'ruby, rails', :on => :tags)
|
94
94
|
@user_y.tag(@taggable, :with => 'ruby, plugin', :on => :tags)
|
95
95
|
|
96
96
|
@user_y.tag(@taggable, :with => '', :on => :tags)
|
97
97
|
@user_y.tag(@taggable, :with => '', :on => :tags)
|
98
98
|
end
|
99
|
-
|
100
|
-
it "should delete owned tags" do
|
99
|
+
|
100
|
+
it "should delete owned tags" do
|
101
101
|
@user_y.owned_tags.should == []
|
102
102
|
end
|
103
|
-
|
103
|
+
|
104
104
|
it "should not delete other taggers tags" do
|
105
105
|
@user_x.owned_tags.should have(2).items
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
it "should not delete original tags" do
|
109
109
|
@taggable.all_tags_list_on(:tags).should include('plugin')
|
110
110
|
end
|