ghazel-acts-as-taggable-on 2.0.6.1

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.
Files changed (39) hide show
  1. data/CHANGELOG +25 -0
  2. data/Gemfile +10 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +221 -0
  5. data/Rakefile +59 -0
  6. data/VERSION +1 -0
  7. data/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb +7 -0
  8. data/generators/acts_as_taggable_on_migration/templates/migration.rb +29 -0
  9. data/lib/acts-as-taggable-on.rb +30 -0
  10. data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +53 -0
  11. data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +53 -0
  12. data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +139 -0
  13. data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +262 -0
  14. data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +105 -0
  15. data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +69 -0
  16. data/lib/acts_as_taggable_on/acts_as_tagger.rb +67 -0
  17. data/lib/acts_as_taggable_on/compatibility/Gemfile +8 -0
  18. data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +21 -0
  19. data/lib/acts_as_taggable_on/tag.rb +84 -0
  20. data/lib/acts_as_taggable_on/tag_list.rb +96 -0
  21. data/lib/acts_as_taggable_on/tagging.rb +24 -0
  22. data/lib/acts_as_taggable_on/tags_helper.rb +17 -0
  23. data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +32 -0
  24. data/lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb +28 -0
  25. data/rails/init.rb +1 -0
  26. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +268 -0
  27. data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +114 -0
  28. data/spec/acts_as_taggable_on/tag_list_spec.rb +70 -0
  29. data/spec/acts_as_taggable_on/tag_spec.rb +115 -0
  30. data/spec/acts_as_taggable_on/taggable_spec.rb +333 -0
  31. data/spec/acts_as_taggable_on/tagger_spec.rb +91 -0
  32. data/spec/acts_as_taggable_on/tagging_spec.rb +31 -0
  33. data/spec/acts_as_taggable_on/tags_helper_spec.rb +28 -0
  34. data/spec/bm.rb +52 -0
  35. data/spec/database.yml.sample +17 -0
  36. data/spec/models.rb +31 -0
  37. data/spec/schema.rb +43 -0
  38. data/spec/spec_helper.rb +60 -0
  39. metadata +114 -0
@@ -0,0 +1,70 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe ActsAsTaggableOn::TagList do
4
+ before(:each) do
5
+ @tag_list = ActsAsTaggableOn::TagList.new("awesome","radical")
6
+ end
7
+
8
+ it "should be an array" do
9
+ @tag_list.is_a?(Array).should be_true
10
+ end
11
+
12
+ it "should be able to be add a new tag word" do
13
+ @tag_list.add("cool")
14
+ @tag_list.include?("cool").should be_true
15
+ end
16
+
17
+ it "should be able to add delimited lists of words" do
18
+ @tag_list.add("cool, wicked", :parse => true)
19
+ @tag_list.include?("cool").should be_true
20
+ @tag_list.include?("wicked").should be_true
21
+ end
22
+
23
+ it "should be able to add delimited list of words with quoted delimiters" do
24
+ @tag_list.add("'cool, wicked', \"really cool, really wicked\"", :parse => true)
25
+ @tag_list.include?("cool, wicked").should be_true
26
+ @tag_list.include?("really cool, really wicked").should be_true
27
+ end
28
+
29
+ it "should be able to handle other uses of quotation marks correctly" do
30
+ @tag_list.add("john's cool car, mary's wicked toy", :parse => true)
31
+ @tag_list.include?("john's cool car").should be_true
32
+ @tag_list.include?("mary's wicked toy").should be_true
33
+ end
34
+
35
+ it "should be able to add an array of words" do
36
+ @tag_list.add(["cool", "wicked"], :parse => true)
37
+ @tag_list.include?("cool").should be_true
38
+ @tag_list.include?("wicked").should be_true
39
+ end
40
+
41
+ it "should be able to remove words" do
42
+ @tag_list.remove("awesome")
43
+ @tag_list.include?("awesome").should be_false
44
+ end
45
+
46
+ it "should be able to remove delimited lists of words" do
47
+ @tag_list.remove("awesome, radical", :parse => true)
48
+ @tag_list.should be_empty
49
+ end
50
+
51
+ it "should be able to remove an array of words" do
52
+ @tag_list.remove(["awesome", "radical"], :parse => true)
53
+ @tag_list.should be_empty
54
+ end
55
+
56
+ it "should give a delimited list of words when converted to string" do
57
+ @tag_list.to_s.should == "awesome, radical"
58
+ end
59
+
60
+ it "should quote escape tags with commas in them" do
61
+ @tag_list.add("cool","rad,bodacious")
62
+ @tag_list.to_s.should == "awesome, radical, cool, \"rad,bodacious\""
63
+ end
64
+
65
+ it "should be able to call to_s on a frozen tag list" do
66
+ @tag_list.freeze
67
+ lambda { @tag_list.add("cool","rad,bodacious") }.should raise_error
68
+ lambda { @tag_list.to_s }.should_not raise_error
69
+ end
70
+ end
@@ -0,0 +1,115 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe ActsAsTaggableOn::Tag do
4
+ before(:each) do
5
+ clean_database!
6
+ @tag = ActsAsTaggableOn::Tag.new
7
+ @user = TaggableModel.create(:name => "Pablo")
8
+ end
9
+
10
+ describe "named like any" do
11
+ before(:each) do
12
+ ActsAsTaggableOn::Tag.create(:name => "awesome")
13
+ ActsAsTaggableOn::Tag.create(:name => "epic")
14
+ end
15
+
16
+ it "should find both tags" do
17
+ ActsAsTaggableOn::Tag.named_like_any(["awesome", "epic"]).should have(2).items
18
+ end
19
+ end
20
+
21
+ describe "find or create by name" do
22
+ before(:each) do
23
+ @tag.name = "awesome"
24
+ @tag.save
25
+ end
26
+
27
+ it "should find by name" do
28
+ ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("awesome").should == @tag
29
+ end
30
+
31
+ it "should find by name case insensitive" do
32
+ ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("AWESOME").should == @tag
33
+ end
34
+
35
+ it "should create by name" do
36
+ lambda {
37
+ ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("epic")
38
+ }.should change(ActsAsTaggableOn::Tag, :count).by(1)
39
+ end
40
+ end
41
+
42
+ describe "find or create all by any name" do
43
+ before(:each) do
44
+ @tag.name = "awesome"
45
+ @tag.save
46
+ end
47
+
48
+ it "should find by name" do
49
+ ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("awesome").should == [@tag]
50
+ end
51
+
52
+ it "should find by name case insensitive" do
53
+ ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("AWESOME").should == [@tag]
54
+ end
55
+
56
+ it "should create by name" do
57
+ lambda {
58
+ ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("epic")
59
+ }.should change(ActsAsTaggableOn::Tag, :count).by(1)
60
+ end
61
+
62
+ it "should find or create by name" do
63
+ lambda {
64
+ ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("awesome", "epic").map(&:name).should == ["awesome", "epic"]
65
+ }.should change(ActsAsTaggableOn::Tag, :count).by(1)
66
+ end
67
+
68
+ it "should return an empty array if no tags are specified" do
69
+ ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name([]).should == []
70
+ end
71
+ end
72
+
73
+ it "should require a name" do
74
+ @tag.valid?
75
+
76
+ if ActiveRecord::VERSION::MAJOR >= 3
77
+ @tag.errors[:name].should == ["can't be blank"]
78
+ else
79
+ @tag.errors[:name].should == "can't be blank"
80
+ end
81
+
82
+ @tag.name = "something"
83
+ @tag.valid?
84
+
85
+ if ActiveRecord::VERSION::MAJOR >= 3
86
+ @tag.errors[:name].should == []
87
+ else
88
+ @tag.errors[:name].should be_nil
89
+ end
90
+ end
91
+
92
+ it "should equal a tag with the same name" do
93
+ @tag.name = "awesome"
94
+ new_tag = ActsAsTaggableOn::Tag.new(:name => "awesome")
95
+ new_tag.should == @tag
96
+ end
97
+
98
+ it "should return its name when to_s is called" do
99
+ @tag.name = "cool"
100
+ @tag.to_s.should == "cool"
101
+ end
102
+
103
+ it "have named_scope named(something)" do
104
+ @tag.name = "cool"
105
+ @tag.save!
106
+ ActsAsTaggableOn::Tag.named('cool').should include(@tag)
107
+ end
108
+
109
+ it "have named_scope named_like(something)" do
110
+ @tag.name = "cool"
111
+ @tag.save!
112
+ @another_tag = ActsAsTaggableOn::Tag.create!(:name => "coolip")
113
+ ActsAsTaggableOn::Tag.named_like('cool').should include(@tag, @another_tag)
114
+ end
115
+ end
@@ -0,0 +1,333 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe "Taggable" do
4
+ before(:each) do
5
+ clean_database!
6
+ @taggable = TaggableModel.new(:name => "Bob Jones")
7
+ @taggables = [@taggable, TaggableModel.new(:name => "John Doe")]
8
+ end
9
+
10
+ it "should have tag types" do
11
+ [:tags, :languages, :skills, :needs, :offerings].each do |type|
12
+ TaggableModel.tag_types.should include type
13
+ end
14
+
15
+ @taggable.tag_types.should == TaggableModel.tag_types
16
+ end
17
+
18
+ it "should have tag_counts_on" do
19
+ TaggableModel.tag_counts_on(:tags).all.should be_empty
20
+
21
+ @taggable.tag_list = ["awesome", "epic"]
22
+ @taggable.save
23
+
24
+ TaggableModel.tag_counts_on(:tags).length.should == 2
25
+ @taggable.tag_counts_on(:tags).length.should == 2
26
+ end
27
+
28
+ it "should be able to create tags" do
29
+ @taggable.skill_list = "ruby, rails, css"
30
+ @taggable.instance_variable_get("@skill_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
31
+
32
+ lambda {
33
+ @taggable.save
34
+ }.should change(ActsAsTaggableOn::Tag, :count).by(3)
35
+
36
+ @taggable.reload
37
+ @taggable.skill_list.sort.should == %w(ruby rails css).sort
38
+ end
39
+
40
+ it "should be able to create tags through the tag list directly" do
41
+ @taggable.tag_list_on(:test).add("hello")
42
+ @taggable.tag_list_cache_on(:test).should_not be_empty
43
+ @taggable.tag_list_on(:test).should == ["hello"]
44
+
45
+ @taggable.save
46
+ @taggable.save_tags
47
+
48
+ @taggable.reload
49
+ @taggable.tag_list_on(:test).should == ["hello"]
50
+ end
51
+
52
+ it "should differentiate between contexts" do
53
+ @taggable.skill_list = "ruby, rails, css"
54
+ @taggable.tag_list = "ruby, bob, charlie"
55
+ @taggable.save
56
+ @taggable.reload
57
+ @taggable.skill_list.should include("ruby")
58
+ @taggable.skill_list.should_not include("bob")
59
+ end
60
+
61
+ it "should be able to remove tags through list alone" do
62
+ @taggable.skill_list = "ruby, rails, css"
63
+ @taggable.save
64
+ @taggable.reload
65
+ @taggable.should have(3).skills
66
+ @taggable.skill_list = "ruby, rails"
67
+ @taggable.save
68
+ @taggable.reload
69
+ @taggable.should have(2).skills
70
+ end
71
+
72
+ it "should be able to select taggables by subset of tags using ActiveRelation methods" do
73
+ @taggables[0].tag_list = "bob"
74
+ @taggables[1].tag_list = "charlie"
75
+ @taggables[0].skill_list = "ruby"
76
+ @taggables[1].skill_list = "css"
77
+ @taggables.each{|taggable| taggable.save}
78
+
79
+ @found_taggables_by_tag = TaggableModel.joins(:tags).where(:tags => {:name => ["bob"]})
80
+ @found_taggables_by_skill = TaggableModel.joins(:skills).where(:tags => {:name => ["ruby"]})
81
+
82
+ @found_taggables_by_tag.should include @taggables[0]
83
+ @found_taggables_by_tag.should_not include @taggables[1]
84
+ @found_taggables_by_skill.should include @taggables[0]
85
+ @found_taggables_by_skill.should_not include @taggables[1]
86
+ end
87
+
88
+ it "should be able to find by tag" do
89
+ @taggable.skill_list = "ruby, rails, css"
90
+ @taggable.save
91
+
92
+ TaggableModel.tagged_with("ruby").first.should == @taggable
93
+ end
94
+
95
+ it "should be able to find by tag with context" do
96
+ @taggable.skill_list = "ruby, rails, css"
97
+ @taggable.tag_list = "bob, charlie"
98
+ @taggable.save
99
+
100
+ TaggableModel.tagged_with("ruby").first.should == @taggable
101
+ TaggableModel.tagged_with("ruby, css").first.should == @taggable
102
+ TaggableModel.tagged_with("bob", :on => :skills).first.should_not == @taggable
103
+ TaggableModel.tagged_with("bob", :on => :tags).first.should == @taggable
104
+ end
105
+
106
+ it "should not care about case" do
107
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby")
108
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "Ruby")
109
+
110
+ ActsAsTaggableOn::Tag.find(:all).size.should == 1
111
+ TaggableModel.tagged_with("ruby").to_a.should == TaggableModel.tagged_with("Ruby").to_a
112
+ end
113
+
114
+ it "should be able to get tag counts on model as a whole" do
115
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
116
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
117
+ charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
118
+ TaggableModel.tag_counts.all.should_not be_empty
119
+ TaggableModel.skill_counts.all.should_not be_empty
120
+ end
121
+
122
+ it "should be able to get all tag counts on model as whole" do
123
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
124
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
125
+ charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
126
+
127
+ TaggableModel.all_tag_counts.all.should_not be_empty
128
+ TaggableModel.all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby
129
+ end
130
+
131
+ if ActiveRecord::VERSION::MAJOR >= 3
132
+ it "should not return read-only records" do
133
+ TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
134
+ TaggableModel.tagged_with("ruby").first.should_not be_readonly
135
+ end
136
+ else
137
+ xit "should not return read-only records" do
138
+ # apparantly, there is no way to set readonly to false in a scope if joins are made
139
+ end
140
+
141
+ it "should be possible to return writable records" do
142
+ TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
143
+ TaggableModel.tagged_with("ruby").first(:readonly => false).should_not be_readonly
144
+ end
145
+ end
146
+
147
+ it "should be able to get scoped tag counts" do
148
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
149
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
150
+ charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
151
+
152
+ TaggableModel.tagged_with("ruby").tag_counts(:order => 'tags.id').first.count.should == 2 # ruby
153
+ TaggableModel.tagged_with("ruby").skill_counts.first.count.should == 1 # ruby
154
+ end
155
+
156
+ it "should be able to get all scoped tag counts" do
157
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
158
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
159
+ charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
160
+
161
+ TaggableModel.tagged_with("ruby").all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby
162
+ end
163
+
164
+ it 'should only return tag counts for the available scope' do
165
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
166
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
167
+ charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby, java")
168
+
169
+ TaggableModel.tagged_with('rails').all_tag_counts.should have(3).items
170
+ TaggableModel.tagged_with('rails').all_tag_counts.any? { |tag| tag.name == 'java' }.should be_false
171
+
172
+ # Test specific join syntaxes:
173
+ frank.untaggable_models.create!
174
+ TaggableModel.tagged_with('rails').scoped(:joins => :untaggable_models).all_tag_counts.should have(2).items
175
+ TaggableModel.tagged_with('rails').scoped(:joins => { :untaggable_models => :taggable_model }).all_tag_counts.should have(2).items
176
+ TaggableModel.tagged_with('rails').scoped(:joins => [:untaggable_models]).all_tag_counts.should have(2).items
177
+ end
178
+
179
+ it "should be able to set a custom tag context list" do
180
+ bob = TaggableModel.create(:name => "Bob")
181
+ bob.set_tag_list_on(:rotors, "spinning, jumping")
182
+ bob.tag_list_on(:rotors).should == ["spinning","jumping"]
183
+ bob.save
184
+ bob.reload
185
+ bob.tags_on(:rotors).should_not be_empty
186
+ end
187
+
188
+ it "should be able to find tagged" do
189
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
190
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
191
+ steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
192
+
193
+ TaggableModel.tagged_with("ruby", :order => 'taggable_models.name').to_a.should == [bob, frank, steve]
194
+ TaggableModel.tagged_with("ruby, rails", :order => 'taggable_models.name').to_a.should == [bob, frank]
195
+ TaggableModel.tagged_with(["ruby", "rails"], :order => 'taggable_models.name').to_a.should == [bob, frank]
196
+ end
197
+
198
+ it "should be able to find tagged with quotation marks" do
199
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive, 'I love the ,comma,'")
200
+ TaggableModel.tagged_with("'I love the ,comma,'").should include(bob)
201
+ end
202
+
203
+ it "should be able to find tagged with invalid tags" do
204
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive")
205
+ TaggableModel.tagged_with("sad, happier").should_not include(bob)
206
+ end
207
+
208
+ it "should be able to find tagged with any tag" do
209
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
210
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
211
+ steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
212
+
213
+ TaggableModel.tagged_with(["ruby", "java"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank, steve]
214
+ TaggableModel.tagged_with(["c++", "fitter"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, steve]
215
+ TaggableModel.tagged_with(["depressed", "css"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank]
216
+ end
217
+
218
+ it "should be able to find tagged on a custom tag context" do
219
+ bob = TaggableModel.create(:name => "Bob")
220
+ bob.set_tag_list_on(:rotors, "spinning, jumping")
221
+ bob.tag_list_on(:rotors).should == ["spinning","jumping"]
222
+ bob.save
223
+
224
+ TaggableModel.tagged_with("spinning", :on => :rotors).to_a.should == [bob]
225
+ end
226
+
227
+ it "should be able to use named scopes to chain tag finds" do
228
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
229
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
230
+ steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, python')
231
+
232
+ # Let's only find those productive Rails developers
233
+ TaggableModel.tagged_with('rails', :on => :skills, :order => 'taggable_models.name').to_a.should == [bob, frank]
234
+ TaggableModel.tagged_with('happier', :on => :tags, :order => 'taggable_models.name').to_a.should == [bob, steve]
235
+ TaggableModel.tagged_with('rails', :on => :skills).tagged_with('happier', :on => :tags).to_a.should == [bob]
236
+ TaggableModel.tagged_with('rails').tagged_with('happier', :on => :tags).to_a.should == [bob]
237
+ end
238
+
239
+ it "should be able to find tagged with only the matching tags" do
240
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "lazy, happier")
241
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "fitter, happier, inefficient")
242
+ steve = TaggableModel.create(:name => 'Steve', :tag_list => "fitter, happier")
243
+
244
+ TaggableModel.tagged_with("fitter, happier", :match_all => true).to_a.should == [steve]
245
+ end
246
+
247
+ it "should be able to find tagged with some excluded tags" do
248
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "happier, lazy")
249
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "happier")
250
+ steve = TaggableModel.create(:name => 'Steve', :tag_list => "happier")
251
+
252
+ TaggableModel.tagged_with("lazy", :exclude => true).to_a.should == [frank, steve]
253
+ end
254
+
255
+ it "should not create duplicate taggings" do
256
+ bob = TaggableModel.create(:name => "Bob")
257
+ lambda {
258
+ bob.tag_list << "happier"
259
+ bob.tag_list << "happier"
260
+ bob.save
261
+ }.should change(ActsAsTaggableOn::Tagging, :count).by(1)
262
+ end
263
+
264
+ describe "Associations" do
265
+ before(:each) do
266
+ @taggable = TaggableModel.create(:tag_list => "awesome, epic")
267
+ end
268
+
269
+ it "should not remove tags when creating associated objects" do
270
+ @taggable.untaggable_models.create!
271
+ @taggable.reload
272
+ @taggable.tag_list.should have(2).items
273
+ end
274
+ end
275
+
276
+ describe "grouped_column_names_for method" do
277
+ it "should return all column names joined for Tag GROUP clause" do
278
+ @taggable.grouped_column_names_for(ActsAsTaggableOn::Tag).should == "tags.id, tags.name"
279
+ end
280
+
281
+ it "should return all column names joined for TaggableModel GROUP clause" do
282
+ @taggable.grouped_column_names_for(TaggableModel).should == "taggable_models.id, taggable_models.name, taggable_models.type"
283
+ end
284
+ end
285
+
286
+ describe "Single Table Inheritance" do
287
+ before do
288
+ @taggable = TaggableModel.new(:name => "taggable")
289
+ @inherited_same = InheritingTaggableModel.new(:name => "inherited same")
290
+ @inherited_different = AlteredInheritingTaggableModel.new(:name => "inherited different")
291
+ end
292
+
293
+ it "should be able to save tags for inherited models" do
294
+ @inherited_same.tag_list = "bob, kelso"
295
+ @inherited_same.save
296
+ InheritingTaggableModel.tagged_with("bob").first.should == @inherited_same
297
+ end
298
+
299
+ it "should find STI tagged models on the superclass" do
300
+ @inherited_same.tag_list = "bob, kelso"
301
+ @inherited_same.save
302
+ TaggableModel.tagged_with("bob").first.should == @inherited_same
303
+ end
304
+
305
+ it "should be able to add on contexts only to some subclasses" do
306
+ @inherited_different.part_list = "fork, spoon"
307
+ @inherited_different.save
308
+ InheritingTaggableModel.tagged_with("fork", :on => :parts).should be_empty
309
+ AlteredInheritingTaggableModel.tagged_with("fork", :on => :parts).first.should == @inherited_different
310
+ end
311
+
312
+ it "should have different tag_counts_on for inherited models" do
313
+ @inherited_same.tag_list = "bob, kelso"
314
+ @inherited_same.save!
315
+ @inherited_different.tag_list = "fork, spoon"
316
+ @inherited_different.save!
317
+
318
+ InheritingTaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso)
319
+ AlteredInheritingTaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(fork spoon)
320
+ TaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso fork spoon)
321
+ end
322
+
323
+ it 'should store same tag without validation conflict' do
324
+ @taggable.tag_list = 'one'
325
+ @taggable.save!
326
+
327
+ @inherited_same.tag_list = 'one'
328
+ @inherited_same.save!
329
+
330
+ @inherited_same.update_attributes! :name => 'foo'
331
+ end
332
+ end
333
+ end