acts-as-taggable-on 2.0.6 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|