acts-as-taggable-on 2.0.6 → 2.4.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +35 -0
- data/Gemfile +2 -9
- data/Guardfile +5 -0
- data/{MIT-LICENSE → MIT-LICENSE.md} +1 -1
- data/README.md +297 -0
- data/Rakefile +9 -55
- data/UPGRADING +14 -0
- data/acts-as-taggable-on.gemspec +32 -0
- data/lib/acts-as-taggable-on/version.rb +4 -0
- data/lib/acts-as-taggable-on.rb +37 -4
- data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +6 -6
- data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +99 -45
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +162 -45
- data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +37 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +40 -15
- data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +28 -18
- data/lib/acts_as_taggable_on/tag.rb +41 -16
- data/lib/acts_as_taggable_on/tag_list.rb +19 -14
- data/lib/acts_as_taggable_on/taggable.rb +102 -0
- data/lib/acts_as_taggable_on/{acts_as_tagger.rb → tagger.rb} +3 -3
- data/lib/acts_as_taggable_on/tagging.rb +12 -2
- data/lib/acts_as_taggable_on/tags_helper.rb +2 -2
- data/lib/acts_as_taggable_on/utils.rb +34 -0
- data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +9 -2
- data/lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb +3 -1
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +333 -54
- data/spec/acts_as_taggable_on/tag_list_spec.rb +117 -61
- data/spec/acts_as_taggable_on/tag_spec.rb +111 -14
- data/spec/acts_as_taggable_on/taggable_spec.rb +330 -34
- data/spec/acts_as_taggable_on/tagger_spec.rb +62 -15
- data/spec/acts_as_taggable_on/tagging_spec.rb +2 -5
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +16 -0
- data/spec/acts_as_taggable_on/utils_spec.rb +21 -0
- data/spec/database.yml.sample +4 -2
- data/spec/generators/acts_as_taggable_on/migration/migration_generator_spec.rb +22 -0
- data/spec/models.rb +28 -1
- data/spec/schema.rb +18 -0
- data/spec/spec_helper.rb +30 -7
- data/uninstall.rb +1 -0
- metadata +174 -57
- data/CHANGELOG +0 -25
- data/README.rdoc +0 -221
- data/VERSION +0 -1
- data/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb +0 -7
- data/generators/acts_as_taggable_on_migration/templates/migration.rb +0 -29
- data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +0 -53
- data/lib/acts_as_taggable_on/compatibility/Gemfile +0 -8
- data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +0 -17
- data/lib/acts_as_taggable_on/compatibility/postgresql.rb +0 -44
- data/spec/database.yml +0 -17
@@ -1,9 +1,119 @@
|
|
1
1
|
require File.expand_path('../../spec_helper', __FILE__)
|
2
2
|
|
3
|
+
describe "Taggable To Preserve Order" do
|
4
|
+
before(:each) do
|
5
|
+
clean_database!
|
6
|
+
@taggable = OrderedTaggableModel.new(:name => "Bob Jones")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have tag types" do
|
10
|
+
[:tags, :colours].each do |type|
|
11
|
+
OrderedTaggableModel.tag_types.should include type
|
12
|
+
end
|
13
|
+
|
14
|
+
@taggable.tag_types.should == OrderedTaggableModel.tag_types
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have tag associations" do
|
18
|
+
[:tags, :colours].each do |type|
|
19
|
+
@taggable.respond_to?(type).should be_true
|
20
|
+
@taggable.respond_to?("#{type.to_s.singularize}_taggings").should be_true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should have tag associations ordered by id" do
|
25
|
+
[:tags, :colours].each do |type|
|
26
|
+
OrderedTaggableModel.reflect_on_association(type).options[:order].should include('id')
|
27
|
+
OrderedTaggableModel.reflect_on_association("#{type.to_s.singularize}_taggings".to_sym).options[:order].should include('id')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should have tag methods" do
|
32
|
+
[:tags, :colours].each do |type|
|
33
|
+
@taggable.respond_to?("#{type.to_s.singularize}_list").should be_true
|
34
|
+
@taggable.respond_to?("#{type.to_s.singularize}_list=").should be_true
|
35
|
+
@taggable.respond_to?("all_#{type.to_s}_list").should be_true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return tag list in the order the tags were created" do
|
40
|
+
# create
|
41
|
+
@taggable.tag_list = "rails, ruby, css"
|
42
|
+
@taggable.instance_variable_get("@tag_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
|
43
|
+
|
44
|
+
lambda {
|
45
|
+
@taggable.save
|
46
|
+
}.should change(ActsAsTaggableOn::Tag, :count).by(3)
|
47
|
+
|
48
|
+
@taggable.reload
|
49
|
+
@taggable.tag_list.should == %w(rails ruby css)
|
50
|
+
|
51
|
+
# update
|
52
|
+
@taggable.tag_list = "pow, ruby, rails"
|
53
|
+
@taggable.save
|
54
|
+
|
55
|
+
@taggable.reload
|
56
|
+
@taggable.tag_list.should == %w(pow ruby rails)
|
57
|
+
|
58
|
+
# update with no change
|
59
|
+
@taggable.tag_list = "pow, ruby, rails"
|
60
|
+
@taggable.save
|
61
|
+
|
62
|
+
@taggable.reload
|
63
|
+
@taggable.tag_list.should == %w(pow ruby rails)
|
64
|
+
|
65
|
+
# update to clear tags
|
66
|
+
@taggable.tag_list = ""
|
67
|
+
@taggable.save
|
68
|
+
|
69
|
+
@taggable.reload
|
70
|
+
@taggable.tag_list.should == []
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should return tag objects in the order the tags were created" do
|
74
|
+
# create
|
75
|
+
@taggable.tag_list = "pow, ruby, rails"
|
76
|
+
@taggable.instance_variable_get("@tag_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
|
77
|
+
|
78
|
+
lambda {
|
79
|
+
@taggable.save
|
80
|
+
}.should change(ActsAsTaggableOn::Tag, :count).by(3)
|
81
|
+
|
82
|
+
@taggable.reload
|
83
|
+
@taggable.tags.map{|t| t.name}.should == %w(pow ruby rails)
|
84
|
+
|
85
|
+
# update
|
86
|
+
@taggable.tag_list = "rails, ruby, css, pow"
|
87
|
+
@taggable.save
|
88
|
+
|
89
|
+
@taggable.reload
|
90
|
+
@taggable.tags.map{|t| t.name}.should == %w(rails ruby css pow)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should return tag objects in tagging id order" do
|
94
|
+
# create
|
95
|
+
@taggable.tag_list = "pow, ruby, rails"
|
96
|
+
@taggable.save
|
97
|
+
|
98
|
+
@taggable.reload
|
99
|
+
ids = @taggable.tags.map{|t| t.taggings.first.id}
|
100
|
+
ids.should == ids.sort
|
101
|
+
|
102
|
+
# update
|
103
|
+
@taggable.tag_list = "rails, ruby, css, pow"
|
104
|
+
@taggable.save
|
105
|
+
|
106
|
+
@taggable.reload
|
107
|
+
ids = @taggable.tags.map{|t| t.taggings.first.id}
|
108
|
+
ids.should == ids.sort
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
3
112
|
describe "Taggable" do
|
4
113
|
before(:each) do
|
5
114
|
clean_database!
|
6
115
|
@taggable = TaggableModel.new(:name => "Bob Jones")
|
116
|
+
@taggables = [@taggable, TaggableModel.new(:name => "John Doe")]
|
7
117
|
end
|
8
118
|
|
9
119
|
it "should have tag types" do
|
@@ -24,14 +134,29 @@ describe "Taggable" do
|
|
24
134
|
@taggable.tag_counts_on(:tags).length.should == 2
|
25
135
|
end
|
26
136
|
|
137
|
+
it "should have tags_on" do
|
138
|
+
TaggableModel.tags_on(:tags).all.should be_empty
|
139
|
+
|
140
|
+
@taggable.tag_list = ["awesome", "epic"]
|
141
|
+
@taggable.save
|
142
|
+
|
143
|
+
TaggableModel.tags_on(:tags).length.should == 2
|
144
|
+
@taggable.tags_on(:tags).length.should == 2
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should return [] right after create" do
|
148
|
+
blank_taggable = TaggableModel.new(:name => "Bob Jones")
|
149
|
+
blank_taggable.tag_list.should == []
|
150
|
+
end
|
151
|
+
|
27
152
|
it "should be able to create tags" do
|
28
153
|
@taggable.skill_list = "ruby, rails, css"
|
29
154
|
@taggable.instance_variable_get("@skill_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
|
30
|
-
|
155
|
+
|
31
156
|
lambda {
|
32
157
|
@taggable.save
|
33
158
|
}.should change(ActsAsTaggableOn::Tag, :count).by(3)
|
34
|
-
|
159
|
+
|
35
160
|
@taggable.reload
|
36
161
|
@taggable.skill_list.sort.should == %w(ruby rails css).sort
|
37
162
|
end
|
@@ -40,10 +165,10 @@ describe "Taggable" do
|
|
40
165
|
@taggable.tag_list_on(:test).add("hello")
|
41
166
|
@taggable.tag_list_cache_on(:test).should_not be_empty
|
42
167
|
@taggable.tag_list_on(:test).should == ["hello"]
|
43
|
-
|
168
|
+
|
44
169
|
@taggable.save
|
45
170
|
@taggable.save_tags
|
46
|
-
|
171
|
+
|
47
172
|
@taggable.reload
|
48
173
|
@taggable.tag_list_on(:test).should == ["hello"]
|
49
174
|
end
|
@@ -68,6 +193,22 @@ describe "Taggable" do
|
|
68
193
|
@taggable.should have(2).skills
|
69
194
|
end
|
70
195
|
|
196
|
+
it "should be able to select taggables by subset of tags using ActiveRelation methods" do
|
197
|
+
@taggables[0].tag_list = "bob"
|
198
|
+
@taggables[1].tag_list = "charlie"
|
199
|
+
@taggables[0].skill_list = "ruby"
|
200
|
+
@taggables[1].skill_list = "css"
|
201
|
+
@taggables.each{|taggable| taggable.save}
|
202
|
+
|
203
|
+
@found_taggables_by_tag = TaggableModel.joins(:tags).where(:tags => {:name => ["bob"]})
|
204
|
+
@found_taggables_by_skill = TaggableModel.joins(:skills).where(:tags => {:name => ["ruby"]})
|
205
|
+
|
206
|
+
@found_taggables_by_tag.should include @taggables[0]
|
207
|
+
@found_taggables_by_tag.should_not include @taggables[1]
|
208
|
+
@found_taggables_by_skill.should include @taggables[0]
|
209
|
+
@found_taggables_by_skill.should_not include @taggables[1]
|
210
|
+
end
|
211
|
+
|
71
212
|
it "should be able to find by tag" do
|
72
213
|
@taggable.skill_list = "ruby, rails, css"
|
73
214
|
@taggable.save
|
@@ -111,20 +252,27 @@ describe "Taggable" do
|
|
111
252
|
TaggableModel.all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby
|
112
253
|
end
|
113
254
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
255
|
+
it "should be able to get all tags on model as whole" do
|
256
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
257
|
+
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
258
|
+
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
|
259
|
+
|
260
|
+
TaggableModel.all_tags.all.should_not be_empty
|
261
|
+
TaggableModel.all_tags(:order => 'tags.id').first.name.should == "ruby"
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should be able to use named scopes to chain tag finds by any tags by context" do
|
265
|
+
bob = TaggableModel.create(:name => "Bob", :need_list => "rails", :offering_list => "c++")
|
266
|
+
frank = TaggableModel.create(:name => "Frank", :need_list => "css", :offering_list => "css")
|
267
|
+
steve = TaggableModel.create(:name => 'Steve', :need_list => "c++", :offering_list => "java")
|
268
|
+
|
269
|
+
# Let's only find those who need rails or css and are offering c++ or java
|
270
|
+
TaggableModel.tagged_with(['rails, css'], :on => :needs, :any => true).tagged_with(['c++', 'java'], :on => :offerings, :any => true).to_a.should == [bob]
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should not return read-only records" do
|
274
|
+
TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
275
|
+
TaggableModel.tagged_with("ruby").first.should_not be_readonly
|
128
276
|
end
|
129
277
|
|
130
278
|
it "should be able to get scoped tag counts" do
|
@@ -144,14 +292,22 @@ describe "Taggable" do
|
|
144
292
|
TaggableModel.tagged_with("ruby").all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby
|
145
293
|
end
|
146
294
|
|
295
|
+
it "should be able to get all scoped tags" do
|
296
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
297
|
+
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
298
|
+
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
|
299
|
+
|
300
|
+
TaggableModel.tagged_with("ruby").all_tags(:order => 'tags.id').first.name.should == "ruby"
|
301
|
+
end
|
302
|
+
|
147
303
|
it 'should only return tag counts for the available scope' do
|
148
304
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
149
305
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
150
306
|
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby, java")
|
151
|
-
|
307
|
+
|
152
308
|
TaggableModel.tagged_with('rails').all_tag_counts.should have(3).items
|
153
309
|
TaggableModel.tagged_with('rails').all_tag_counts.any? { |tag| tag.name == 'java' }.should be_false
|
154
|
-
|
310
|
+
|
155
311
|
# Test specific join syntaxes:
|
156
312
|
frank.untaggable_models.create!
|
157
313
|
TaggableModel.tagged_with('rails').scoped(:joins => :untaggable_models).all_tag_counts.should have(2).items
|
@@ -159,6 +315,21 @@ describe "Taggable" do
|
|
159
315
|
TaggableModel.tagged_with('rails').scoped(:joins => [:untaggable_models]).all_tag_counts.should have(2).items
|
160
316
|
end
|
161
317
|
|
318
|
+
it 'should only return tags for the available scope' do
|
319
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
320
|
+
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
321
|
+
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby, java")
|
322
|
+
|
323
|
+
TaggableModel.tagged_with('rails').all_tags.should have(3).items
|
324
|
+
TaggableModel.tagged_with('rails').all_tags.any? { |tag| tag.name == 'java' }.should be_false
|
325
|
+
|
326
|
+
# Test specific join syntaxes:
|
327
|
+
frank.untaggable_models.create!
|
328
|
+
TaggableModel.tagged_with('rails').scoped(:joins => :untaggable_models).all_tags.should have(2).items
|
329
|
+
TaggableModel.tagged_with('rails').scoped(:joins => { :untaggable_models => :taggable_model }).all_tags.should have(2).items
|
330
|
+
TaggableModel.tagged_with('rails').scoped(:joins => [:untaggable_models]).all_tags.should have(2).items
|
331
|
+
end
|
332
|
+
|
162
333
|
it "should be able to set a custom tag context list" do
|
163
334
|
bob = TaggableModel.create(:name => "Bob")
|
164
335
|
bob.set_tag_list_on(:rotors, "spinning, jumping")
|
@@ -177,15 +348,15 @@ describe "Taggable" do
|
|
177
348
|
TaggableModel.tagged_with("ruby, rails", :order => 'taggable_models.name').to_a.should == [bob, frank]
|
178
349
|
TaggableModel.tagged_with(["ruby", "rails"], :order => 'taggable_models.name').to_a.should == [bob, frank]
|
179
350
|
end
|
180
|
-
|
351
|
+
|
181
352
|
it "should be able to find tagged with quotation marks" do
|
182
353
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive, 'I love the ,comma,'")
|
183
354
|
TaggableModel.tagged_with("'I love the ,comma,'").should include(bob)
|
184
355
|
end
|
185
|
-
|
356
|
+
|
186
357
|
it "should be able to find tagged with invalid tags" do
|
187
|
-
bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive")
|
188
|
-
TaggableModel.tagged_with("sad, happier").should_not include(bob)
|
358
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive")
|
359
|
+
TaggableModel.tagged_with("sad, happier").should_not include(bob)
|
189
360
|
end
|
190
361
|
|
191
362
|
it "should be able to find tagged with any tag" do
|
@@ -198,6 +369,19 @@ describe "Taggable" do
|
|
198
369
|
TaggableModel.tagged_with(["depressed", "css"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank]
|
199
370
|
end
|
200
371
|
|
372
|
+
context "wild: true" do
|
373
|
+
it "should use params as wildcards" do
|
374
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "bob, tricia")
|
375
|
+
frank = TaggableModel.create(:name => "Frank", :tag_list => "bobby, jim")
|
376
|
+
steve = TaggableModel.create(:name => "Steve", :tag_list => "john, patricia")
|
377
|
+
jim = TaggableModel.create(:name => "Jim", :tag_list => "jim, steve")
|
378
|
+
|
379
|
+
|
380
|
+
TaggableModel.tagged_with(["bob", "tricia"], :wild => true, :any => true).to_a.sort_by{|o| o.id}.should == [bob, frank, steve]
|
381
|
+
TaggableModel.tagged_with(["bob", "tricia"], :wild => true, :exclude => true).to_a.should == [jim]
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
201
385
|
it "should be able to find tagged on a custom tag context" do
|
202
386
|
bob = TaggableModel.create(:name => "Bob")
|
203
387
|
bob.set_tag_list_on(:rotors, "spinning, jumping")
|
@@ -235,6 +419,13 @@ describe "Taggable" do
|
|
235
419
|
TaggableModel.tagged_with("lazy", :exclude => true).to_a.should == [frank, steve]
|
236
420
|
end
|
237
421
|
|
422
|
+
it "should return an empty scope for empty tags" do
|
423
|
+
TaggableModel.tagged_with('').should == []
|
424
|
+
TaggableModel.tagged_with(' ').should == []
|
425
|
+
TaggableModel.tagged_with(nil).should == []
|
426
|
+
TaggableModel.tagged_with([]).should == []
|
427
|
+
end
|
428
|
+
|
238
429
|
it "should not create duplicate taggings" do
|
239
430
|
bob = TaggableModel.create(:name => "Bob")
|
240
431
|
lambda {
|
@@ -243,12 +434,12 @@ describe "Taggable" do
|
|
243
434
|
bob.save
|
244
435
|
}.should change(ActsAsTaggableOn::Tagging, :count).by(1)
|
245
436
|
end
|
246
|
-
|
437
|
+
|
247
438
|
describe "Associations" do
|
248
439
|
before(:each) do
|
249
440
|
@taggable = TaggableModel.create(:tag_list => "awesome, epic")
|
250
441
|
end
|
251
|
-
|
442
|
+
|
252
443
|
it "should not remove tags when creating associated objects" do
|
253
444
|
@taggable.untaggable_models.create!
|
254
445
|
@taggable.reload
|
@@ -264,6 +455,10 @@ describe "Taggable" do
|
|
264
455
|
it "should return all column names joined for TaggableModel GROUP clause" do
|
265
456
|
@taggable.grouped_column_names_for(TaggableModel).should == "taggable_models.id, taggable_models.name, taggable_models.type"
|
266
457
|
end
|
458
|
+
|
459
|
+
it "should return all column names joined for NonStandardIdTaggableModel GROUP clause" do
|
460
|
+
@taggable.grouped_column_names_for(TaggableModel).should == "taggable_models.#{TaggableModel.primary_key}, taggable_models.name, taggable_models.type"
|
461
|
+
end
|
267
462
|
end
|
268
463
|
|
269
464
|
describe "Single Table Inheritance" do
|
@@ -272,45 +467,146 @@ describe "Taggable" do
|
|
272
467
|
@inherited_same = InheritingTaggableModel.new(:name => "inherited same")
|
273
468
|
@inherited_different = AlteredInheritingTaggableModel.new(:name => "inherited different")
|
274
469
|
end
|
275
|
-
|
470
|
+
|
276
471
|
it "should be able to save tags for inherited models" do
|
277
472
|
@inherited_same.tag_list = "bob, kelso"
|
278
473
|
@inherited_same.save
|
279
474
|
InheritingTaggableModel.tagged_with("bob").first.should == @inherited_same
|
280
475
|
end
|
281
|
-
|
476
|
+
|
282
477
|
it "should find STI tagged models on the superclass" do
|
283
478
|
@inherited_same.tag_list = "bob, kelso"
|
284
479
|
@inherited_same.save
|
285
480
|
TaggableModel.tagged_with("bob").first.should == @inherited_same
|
286
481
|
end
|
287
|
-
|
482
|
+
|
288
483
|
it "should be able to add on contexts only to some subclasses" do
|
289
484
|
@inherited_different.part_list = "fork, spoon"
|
290
485
|
@inherited_different.save
|
291
486
|
InheritingTaggableModel.tagged_with("fork", :on => :parts).should be_empty
|
292
487
|
AlteredInheritingTaggableModel.tagged_with("fork", :on => :parts).first.should == @inherited_different
|
293
488
|
end
|
294
|
-
|
489
|
+
|
295
490
|
it "should have different tag_counts_on for inherited models" do
|
296
491
|
@inherited_same.tag_list = "bob, kelso"
|
297
492
|
@inherited_same.save!
|
298
493
|
@inherited_different.tag_list = "fork, spoon"
|
299
494
|
@inherited_different.save!
|
300
|
-
|
495
|
+
|
301
496
|
InheritingTaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso)
|
302
497
|
AlteredInheritingTaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(fork spoon)
|
303
498
|
TaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso fork spoon)
|
304
499
|
end
|
305
|
-
|
500
|
+
|
501
|
+
it "should have different tags_on for inherited models" do
|
502
|
+
@inherited_same.tag_list = "bob, kelso"
|
503
|
+
@inherited_same.save!
|
504
|
+
@inherited_different.tag_list = "fork, spoon"
|
505
|
+
@inherited_different.save!
|
506
|
+
|
507
|
+
InheritingTaggableModel.tags_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso)
|
508
|
+
AlteredInheritingTaggableModel.tags_on(:tags, :order => 'tags.id').map(&:name).should == %w(fork spoon)
|
509
|
+
TaggableModel.tags_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso fork spoon)
|
510
|
+
end
|
511
|
+
|
306
512
|
it 'should store same tag without validation conflict' do
|
307
513
|
@taggable.tag_list = 'one'
|
308
514
|
@taggable.save!
|
309
|
-
|
515
|
+
|
310
516
|
@inherited_same.tag_list = 'one'
|
311
517
|
@inherited_same.save!
|
312
|
-
|
518
|
+
|
313
519
|
@inherited_same.update_attributes! :name => 'foo'
|
314
520
|
end
|
315
521
|
end
|
522
|
+
|
523
|
+
describe "NonStandardIdTaggable" do
|
524
|
+
before(:each) do
|
525
|
+
clean_database!
|
526
|
+
@taggable = NonStandardIdTaggableModel.new(:name => "Bob Jones")
|
527
|
+
@taggables = [@taggable, NonStandardIdTaggableModel.new(:name => "John Doe")]
|
528
|
+
end
|
529
|
+
|
530
|
+
it "should have tag types" do
|
531
|
+
[:tags, :languages, :skills, :needs, :offerings].each do |type|
|
532
|
+
NonStandardIdTaggableModel.tag_types.should include type
|
533
|
+
end
|
534
|
+
|
535
|
+
@taggable.tag_types.should == NonStandardIdTaggableModel.tag_types
|
536
|
+
end
|
537
|
+
|
538
|
+
it "should have tag_counts_on" do
|
539
|
+
NonStandardIdTaggableModel.tag_counts_on(:tags).all.should be_empty
|
540
|
+
|
541
|
+
@taggable.tag_list = ["awesome", "epic"]
|
542
|
+
@taggable.save
|
543
|
+
|
544
|
+
NonStandardIdTaggableModel.tag_counts_on(:tags).length.should == 2
|
545
|
+
@taggable.tag_counts_on(:tags).length.should == 2
|
546
|
+
end
|
547
|
+
|
548
|
+
it "should have tags_on" do
|
549
|
+
NonStandardIdTaggableModel.tags_on(:tags).all.should be_empty
|
550
|
+
|
551
|
+
@taggable.tag_list = ["awesome", "epic"]
|
552
|
+
@taggable.save
|
553
|
+
|
554
|
+
NonStandardIdTaggableModel.tags_on(:tags).length.should == 2
|
555
|
+
@taggable.tags_on(:tags).length.should == 2
|
556
|
+
end
|
557
|
+
|
558
|
+
it "should be able to create tags" do
|
559
|
+
@taggable.skill_list = "ruby, rails, css"
|
560
|
+
@taggable.instance_variable_get("@skill_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
|
561
|
+
|
562
|
+
lambda {
|
563
|
+
@taggable.save
|
564
|
+
}.should change(ActsAsTaggableOn::Tag, :count).by(3)
|
565
|
+
|
566
|
+
@taggable.reload
|
567
|
+
@taggable.skill_list.sort.should == %w(ruby rails css).sort
|
568
|
+
end
|
569
|
+
|
570
|
+
it "should be able to create tags through the tag list directly" do
|
571
|
+
@taggable.tag_list_on(:test).add("hello")
|
572
|
+
@taggable.tag_list_cache_on(:test).should_not be_empty
|
573
|
+
@taggable.tag_list_on(:test).should == ["hello"]
|
574
|
+
|
575
|
+
@taggable.save
|
576
|
+
@taggable.save_tags
|
577
|
+
|
578
|
+
@taggable.reload
|
579
|
+
@taggable.tag_list_on(:test).should == ["hello"]
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
describe "Dirty Objects" do
|
584
|
+
before(:each) do
|
585
|
+
@taggable = TaggableModel.create(:tag_list => "awesome, epic")
|
586
|
+
end
|
587
|
+
|
588
|
+
it 'should show changes of dirty object' do
|
589
|
+
@taggable.changes.should == {}
|
590
|
+
@taggable.tag_list = 'one'
|
591
|
+
@taggable.changes.should == {"tag_list"=>["awesome, epic", ["one"]]}
|
592
|
+
|
593
|
+
@taggable.tag_list_changed?.should be_true
|
594
|
+
@taggable.tag_list_was.should == "awesome, epic"
|
595
|
+
@taggable.tag_list_change.should == ["awesome, epic", ["one"]]
|
596
|
+
end
|
597
|
+
|
598
|
+
it 'should show no changes if the same tag_list' do
|
599
|
+
@taggable.tag_list = "awesome, epic"
|
600
|
+
@taggable.tag_list_changed?.should be_false
|
601
|
+
@taggable.changes.should == {}
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
describe "Autogenerated methods" do
|
606
|
+
it "should be overridable" do
|
607
|
+
TaggableModel.create(:tag_list=>'woo').tag_list_submethod_called.should be_true
|
608
|
+
end
|
609
|
+
end
|
316
610
|
end
|
611
|
+
|
612
|
+
|
@@ -16,7 +16,21 @@ describe "Tagger" do
|
|
16
16
|
@user.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)
|
17
17
|
@user.owned_tags.size == 2
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
|
+
it "should scope objects returned by tagged_with by owners" do
|
21
|
+
@taggable2 = TaggableModel.create(:name => "Jim Jones")
|
22
|
+
@taggable3 = TaggableModel.create(:name => "Jane Doe")
|
23
|
+
|
24
|
+
@user2 = TaggableUser.new
|
25
|
+
@user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)
|
26
|
+
@user2.tag(@taggable2, :with => 'ruby, scheme', :on => :tags)
|
27
|
+
@user2.tag(@taggable3, :with => 'ruby, scheme', :on => :tags)
|
28
|
+
|
29
|
+
TaggableModel.tagged_with(%w(ruby scheme), :owned_by => @user).count.should == 1
|
30
|
+
TaggableModel.tagged_with(%w(ruby scheme), :owned_by => @user2).count.should == 2
|
31
|
+
|
32
|
+
end
|
33
|
+
|
20
34
|
it "should not overlap tags from different taggers" do
|
21
35
|
@user2 = TaggableUser.new
|
22
36
|
lambda{
|
@@ -28,35 +42,35 @@ describe "Tagger" do
|
|
28
42
|
|
29
43
|
@user.owned_tags.map(&:name).sort.should == %w(ruby scheme).sort
|
30
44
|
@user2.owned_tags.map(&:name).sort.should == %w(java python lisp ruby).sort
|
31
|
-
|
45
|
+
|
32
46
|
@taggable.tags_from(@user).sort.should == %w(ruby scheme).sort
|
33
47
|
@taggable.tags_from(@user2).sort.should == %w(java lisp python ruby).sort
|
34
|
-
|
48
|
+
|
35
49
|
@taggable.all_tags_list.sort.should == %w(ruby scheme java python lisp).sort
|
36
50
|
@taggable.all_tags_on(:tags).size.should == 5
|
37
51
|
end
|
38
|
-
|
52
|
+
|
39
53
|
it "should not lose tags from different taggers" do
|
40
54
|
@user2 = TaggableUser.create
|
41
55
|
@user2.tag(@taggable, :with => 'java, python, lisp, ruby', :on => :tags)
|
42
|
-
@user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)
|
43
|
-
|
56
|
+
@user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)
|
57
|
+
|
44
58
|
lambda {
|
45
59
|
@user2.tag(@taggable, :with => 'java, python, lisp', :on => :tags)
|
46
60
|
}.should change(ActsAsTaggableOn::Tagging, :count).by(-1)
|
47
61
|
|
48
62
|
[@user, @user2, @taggable].each(&:reload)
|
49
|
-
|
63
|
+
|
50
64
|
@taggable.tags_from(@user).sort.should == %w(ruby scheme).sort
|
51
65
|
@taggable.tags_from(@user2).sort.should == %w(java python lisp).sort
|
52
|
-
|
66
|
+
|
53
67
|
@taggable.all_tags_list.sort.should == %w(ruby scheme java python lisp).sort
|
54
68
|
@taggable.all_tags_on(:tags).length.should == 5
|
55
69
|
end
|
56
70
|
|
57
71
|
it "should not lose tags" do
|
58
72
|
@user2 = TaggableUser.create
|
59
|
-
|
73
|
+
|
60
74
|
@user.tag(@taggable, :with => 'awesome', :on => :tags)
|
61
75
|
@user2.tag(@taggable, :with => 'awesome, epic', :on => :tags)
|
62
76
|
|
@@ -64,28 +78,61 @@ describe "Tagger" do
|
|
64
78
|
@user2.tag(@taggable, :with => 'epic', :on => :tags)
|
65
79
|
}.should change(ActsAsTaggableOn::Tagging, :count).by(-1)
|
66
80
|
|
67
|
-
@taggable.reload
|
81
|
+
@taggable.reload
|
68
82
|
@taggable.all_tags_list.should include('awesome')
|
69
83
|
@taggable.all_tags_list.should include('epic')
|
70
84
|
end
|
71
|
-
|
85
|
+
|
72
86
|
it "should not lose tags" do
|
73
87
|
@taggable.update_attributes(:tag_list => 'ruby')
|
74
88
|
@user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)
|
75
|
-
|
89
|
+
|
76
90
|
[@taggable, @user].each(&:reload)
|
77
91
|
@taggable.tag_list.should == %w(ruby)
|
78
92
|
@taggable.all_tags_list.sort.should == %w(ruby scheme).sort
|
79
|
-
|
93
|
+
|
80
94
|
lambda {
|
81
95
|
@taggable.update_attributes(:tag_list => "")
|
82
96
|
}.should change(ActsAsTaggableOn::Tagging, :count).by(-1)
|
83
|
-
|
97
|
+
|
84
98
|
@taggable.tag_list.should == []
|
85
99
|
@taggable.all_tags_list.sort.should == %w(ruby scheme).sort
|
86
100
|
end
|
87
101
|
|
88
102
|
it "is tagger" do
|
89
103
|
@user.is_tagger?.should(be_true)
|
90
|
-
end
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should skip save if skip_save is passed as option" do
|
107
|
+
lambda {
|
108
|
+
@user.tag(@taggable, :with => 'epic', :on => :tags, :skip_save => true)
|
109
|
+
}.should_not change(ActsAsTaggableOn::Tagging, :count)
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "Single Table Inheritance" do
|
113
|
+
before do
|
114
|
+
@user3 = InheritingTaggableUser.create
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should have taggings" do
|
118
|
+
@user3.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)
|
119
|
+
@user3.owned_taggings.size == 2
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should have tags" do
|
123
|
+
@user3.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)
|
124
|
+
@user3.owned_tags.size == 2
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should return tags for the inheriting tagger" do
|
128
|
+
@user3.tag(@taggable, :with => 'ruby, scheme', :on => :tags)
|
129
|
+
@taggable.tags_from(@user3).sort.should == %w(ruby scheme).sort
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should scope objects returned by tagged_with by owners" do
|
133
|
+
@user3.tag(@taggable, :with => 'ruby, scheme', :on => :tags)
|
134
|
+
TaggableModel.tagged_with(%w(ruby scheme), :owned_by => @user3).count.should == 1
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
91
138
|
end
|
@@ -13,11 +13,7 @@ describe ActsAsTaggableOn::Tagging do
|
|
13
13
|
|
14
14
|
@tagging.should_not be_valid
|
15
15
|
|
16
|
-
|
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
|