acts-as-taggable-on 2.3.3 → 2.4.0.beta
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 +2 -2
- data/{CHANGELOG → CHANGELOG.md} +8 -8
- data/{MIT-LICENSE → MIT-LICENSE.md} +1 -1
- data/README.md +297 -0
- data/lib/acts-as-taggable-on.rb +3 -0
- data/lib/acts-as-taggable-on/version.rb +1 -1
- data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +2 -2
- data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +66 -7
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +11 -5
- data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +2 -2
- data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +3 -3
- data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +7 -5
- data/lib/acts_as_taggable_on/tag.rb +32 -10
- data/lib/acts_as_taggable_on/tag_list.rb +2 -2
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +33 -0
- data/spec/acts_as_taggable_on/tag_list_spec.rb +2 -2
- data/spec/acts_as_taggable_on/tag_spec.rb +60 -1
- data/spec/acts_as_taggable_on/taggable_spec.rb +69 -0
- data/spec/models.rb +6 -0
- metadata +62 -46
- data/README.rdoc +0 -244
@@ -14,6 +14,7 @@ module ActsAsTaggableOn::Taggable
|
|
14
14
|
|
15
15
|
module ClassMethods
|
16
16
|
def initialize_acts_as_taggable_on_core
|
17
|
+
include taggable_mixin
|
17
18
|
tag_types.map(&:to_s).each do |tags_type|
|
18
19
|
tag_type = tags_type.to_s.singularize
|
19
20
|
context_taggings = "#{tag_type}_taggings".to_sym
|
@@ -36,7 +37,7 @@ module ActsAsTaggableOn::Taggable
|
|
36
37
|
:order => taggings_order
|
37
38
|
end
|
38
39
|
|
39
|
-
class_eval
|
40
|
+
taggable_mixin.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
40
41
|
def #{tag_type}_list
|
41
42
|
tag_list_on('#{tags_type}')
|
42
43
|
end
|
@@ -48,7 +49,7 @@ module ActsAsTaggableOn::Taggable
|
|
48
49
|
def all_#{tags_type}_list
|
49
50
|
all_tags_list_on('#{tags_type}')
|
50
51
|
end
|
51
|
-
|
52
|
+
RUBY
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
@@ -189,6 +190,10 @@ module ActsAsTaggableOn::Taggable
|
|
189
190
|
end
|
190
191
|
taggings_alias
|
191
192
|
end
|
193
|
+
|
194
|
+
def taggable_mixin
|
195
|
+
@taggable_mixin ||= Module.new
|
196
|
+
end
|
192
197
|
end
|
193
198
|
|
194
199
|
module InstanceMethods
|
@@ -215,12 +220,13 @@ module ActsAsTaggableOn::Taggable
|
|
215
220
|
|
216
221
|
def tag_list_cache_set_on(context)
|
217
222
|
variable_name = "@#{context.to_s.singularize}_list"
|
218
|
-
!instance_variable_get(variable_name).nil?
|
223
|
+
instance_variable_defined?(variable_name) && !instance_variable_get(variable_name).nil?
|
219
224
|
end
|
220
225
|
|
221
226
|
def tag_list_cache_on(context)
|
222
227
|
variable_name = "@#{context.to_s.singularize}_list"
|
223
|
-
instance_variable_get(variable_name)
|
228
|
+
return instance_variable_get(variable_name) if instance_variable_defined?(variable_name) && instance_variable_get(variable_name)
|
229
|
+
instance_variable_set(variable_name, ActsAsTaggableOn::TagList.new(tags_on(context).map(&:name)))
|
224
230
|
end
|
225
231
|
|
226
232
|
def tag_list_on(context)
|
@@ -230,7 +236,7 @@ module ActsAsTaggableOn::Taggable
|
|
230
236
|
|
231
237
|
def all_tags_list_on(context)
|
232
238
|
variable_name = "@all_#{context.to_s.singularize}_list"
|
233
|
-
return instance_variable_get(variable_name) if instance_variable_get(variable_name)
|
239
|
+
return instance_variable_get(variable_name) if instance_variable_defined?(variable_name) && instance_variable_get(variable_name)
|
234
240
|
|
235
241
|
instance_variable_set(variable_name, ActsAsTaggableOn::TagList.new(all_tags_on(context).map(&:name)).freeze)
|
236
242
|
end
|
@@ -12,7 +12,7 @@ module ActsAsTaggableOn::Taggable
|
|
12
12
|
tag_type = tags_type.to_s.singularize
|
13
13
|
context_tags = tags_type.to_sym
|
14
14
|
|
15
|
-
class_eval
|
15
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
16
16
|
def #{tag_type}_list_changed?
|
17
17
|
changed_attributes.include?("#{tag_type}_list")
|
18
18
|
end
|
@@ -28,7 +28,7 @@ module ActsAsTaggableOn::Taggable
|
|
28
28
|
def #{tag_type}_list_changes
|
29
29
|
[changed_attributes['#{tag_type}_list'], __send__('#{tag_type}_list')] if changed_attributes.include?("#{tag_type}_list")
|
30
30
|
end
|
31
|
-
|
31
|
+
RUBY
|
32
32
|
|
33
33
|
end
|
34
34
|
end
|
@@ -19,11 +19,11 @@ module ActsAsTaggableOn::Taggable
|
|
19
19
|
|
20
20
|
def initialize_acts_as_taggable_on_ownership
|
21
21
|
tag_types.map(&:to_s).each do |tag_type|
|
22
|
-
class_eval
|
22
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
23
23
|
def #{tag_type}_from(owner)
|
24
24
|
owner_tag_list_on(owner, '#{tag_type}')
|
25
25
|
end
|
26
|
-
|
26
|
+
RUBY
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -45,7 +45,7 @@ module ActsAsTaggableOn::Taggable
|
|
45
45
|
|
46
46
|
def cached_owned_tag_list_on(context)
|
47
47
|
variable_name = "@owned_#{context}_list"
|
48
|
-
cache = instance_variable_get(variable_name) || instance_variable_set(variable_name, {})
|
48
|
+
cache = (instance_variable_defined?(variable_name) && instance_variable_get(variable_name)) || instance_variable_set(variable_name, {})
|
49
49
|
end
|
50
50
|
|
51
51
|
def owner_tag_list_on(owner, context)
|
@@ -9,7 +9,7 @@ module ActsAsTaggableOn::Taggable
|
|
9
9
|
module ClassMethods
|
10
10
|
def initialize_acts_as_taggable_on_related
|
11
11
|
tag_types.map(&:to_s).each do |tag_type|
|
12
|
-
class_eval
|
12
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
13
13
|
def find_related_#{tag_type}(options = {})
|
14
14
|
related_tags_for('#{tag_type}', self.class, options)
|
15
15
|
end
|
@@ -18,11 +18,11 @@ module ActsAsTaggableOn::Taggable
|
|
18
18
|
def find_related_#{tag_type}_for(klass, options = {})
|
19
19
|
related_tags_for('#{tag_type}', klass, options)
|
20
20
|
end
|
21
|
-
|
21
|
+
RUBY
|
22
22
|
end
|
23
23
|
|
24
24
|
unless tag_types.empty?
|
25
|
-
class_eval
|
25
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
26
26
|
def find_matching_contexts(search_context, result_context, options = {})
|
27
27
|
matching_contexts_for(search_context.to_s, result_context.to_s, self.class, options)
|
28
28
|
end
|
@@ -30,7 +30,7 @@ module ActsAsTaggableOn::Taggable
|
|
30
30
|
def find_matching_contexts_for(klass, search_context, result_context, options = {})
|
31
31
|
matching_contexts_for(search_context.to_s, result_context.to_s, klass, options)
|
32
32
|
end
|
33
|
-
|
33
|
+
RUBY
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -56,7 +56,9 @@ module ActsAsTaggableOn::Taggable
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def related_tags_for(context, klass, options = {})
|
59
|
-
|
59
|
+
tags_to_ignore = Array.wrap(options.delete(:ignore)) || []
|
60
|
+
tags_to_ignore.map! { |t| t.to_s }
|
61
|
+
tags_to_find = tags_on(context).collect { |t| t.name }.reject { |t| tags_to_ignore.include? t }
|
60
62
|
|
61
63
|
exclude_self = "#{klass.table_name}.#{klass.primary_key} != #{id} AND" if [self.class.base_class, self.class].include? klass
|
62
64
|
|
@@ -11,17 +11,30 @@ module ActsAsTaggableOn
|
|
11
11
|
### VALIDATIONS:
|
12
12
|
|
13
13
|
validates_presence_of :name
|
14
|
-
validates_uniqueness_of :name
|
14
|
+
validates_uniqueness_of :name, :if => :validates_name_uniqueness?
|
15
15
|
validates_length_of :name, :maximum => 255
|
16
16
|
|
17
|
+
# monkey patch this method if don't need name uniqueness validation
|
18
|
+
def validates_name_uniqueness?
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
17
22
|
### SCOPES:
|
18
23
|
|
19
24
|
def self.named(name)
|
20
|
-
|
25
|
+
if ActsAsTaggableOn.strict_case_match
|
26
|
+
where(["name = #{binary}?", name])
|
27
|
+
else
|
28
|
+
where(["lower(name) = ?", name.downcase])
|
29
|
+
end
|
21
30
|
end
|
22
31
|
|
23
32
|
def self.named_any(list)
|
24
|
-
|
33
|
+
if ActsAsTaggableOn.strict_case_match
|
34
|
+
where(list.map { |tag| sanitize_sql(["name = #{binary}?", tag.to_s.mb_chars]) }.join(" OR "))
|
35
|
+
else
|
36
|
+
where(list.map { |tag| sanitize_sql(["lower(name) = ?", tag.to_s.mb_chars.downcase]) }.join(" OR "))
|
37
|
+
end
|
25
38
|
end
|
26
39
|
|
27
40
|
def self.named_like(name)
|
@@ -35,7 +48,11 @@ module ActsAsTaggableOn
|
|
35
48
|
### CLASS METHODS:
|
36
49
|
|
37
50
|
def self.find_or_create_with_like_by_name(name)
|
38
|
-
|
51
|
+
if (ActsAsTaggableOn.strict_case_match)
|
52
|
+
self.find_or_create_all_with_like_by_name([name]).first
|
53
|
+
else
|
54
|
+
named_like(name).first || create(:name => name)
|
55
|
+
end
|
39
56
|
end
|
40
57
|
|
41
58
|
def self.find_or_create_all_with_like_by_name(*list)
|
@@ -45,9 +62,9 @@ module ActsAsTaggableOn
|
|
45
62
|
|
46
63
|
existing_tags = Tag.named_any(list).all
|
47
64
|
new_tag_names = list.reject do |name|
|
48
|
-
|
49
|
-
|
50
|
-
|
65
|
+
name = comparable_name(name)
|
66
|
+
existing_tags.any? { |tag| comparable_name(tag.name) == name }
|
67
|
+
end
|
51
68
|
created_tags = new_tag_names.map { |name| Tag.create(:name => name) }
|
52
69
|
|
53
70
|
existing_tags + created_tags
|
@@ -69,9 +86,14 @@ module ActsAsTaggableOn
|
|
69
86
|
|
70
87
|
class << self
|
71
88
|
private
|
72
|
-
|
73
|
-
|
74
|
-
|
89
|
+
|
90
|
+
def comparable_name(str)
|
91
|
+
str.mb_chars.downcase.to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
def binary
|
95
|
+
/mysql/ === ActiveRecord::Base.connection_config[:adapter] ? "BINARY " : nil
|
96
|
+
end
|
75
97
|
end
|
76
98
|
end
|
77
99
|
end
|
@@ -58,7 +58,7 @@ module ActsAsTaggableOn
|
|
58
58
|
end
|
59
59
|
|
60
60
|
##
|
61
|
-
# Transform the tag_list into a tag string suitable for
|
61
|
+
# Transform the tag_list into a tag string suitable for editing in a form.
|
62
62
|
# The tags are joined with <tt>TagList.delimiter</tt> and quoted if necessary.
|
63
63
|
#
|
64
64
|
# Example:
|
@@ -81,7 +81,7 @@ module ActsAsTaggableOn
|
|
81
81
|
def clean!
|
82
82
|
reject!(&:blank?)
|
83
83
|
map!(&:strip)
|
84
|
-
map!
|
84
|
+
map!{ |tag| tag.mb_chars.downcase.to_s } if ActsAsTaggableOn.force_lowercase
|
85
85
|
map!(&:parameterize) if ActsAsTaggableOn.force_parameterize
|
86
86
|
|
87
87
|
uniq!
|
@@ -185,6 +185,39 @@ describe "Acts As Taggable On" do
|
|
185
185
|
taggable1.find_related_tags.should_not include(taggable1)
|
186
186
|
end
|
187
187
|
|
188
|
+
context "Ignored Tags" do
|
189
|
+
let(:taggable1) { TaggableModel.create!(:name => "Taggable 1") }
|
190
|
+
let(:taggable2) { TaggableModel.create!(:name => "Taggable 2") }
|
191
|
+
let(:taggable3) { TaggableModel.create!(:name => "Taggable 3") }
|
192
|
+
before(:each) do
|
193
|
+
taggable1.tag_list = "one, two, four"
|
194
|
+
taggable1.save
|
195
|
+
|
196
|
+
taggable2.tag_list = "two, three"
|
197
|
+
taggable2.save
|
198
|
+
|
199
|
+
taggable3.tag_list = "one, three"
|
200
|
+
taggable3.save
|
201
|
+
end
|
202
|
+
it "should not include ignored tags in related search" do
|
203
|
+
taggable1.find_related_tags(:ignore => 'two').should_not include(taggable2)
|
204
|
+
taggable1.find_related_tags(:ignore => 'two').should include(taggable3)
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should accept array of ignored tags" do
|
208
|
+
taggable4 = TaggableModel.create!(:name => "Taggable 4")
|
209
|
+
taggable4.tag_list = "four"
|
210
|
+
taggable4.save
|
211
|
+
|
212
|
+
taggable1.find_related_tags(:ignore => ['two', 'four']).should_not include(taggable2)
|
213
|
+
taggable1.find_related_tags(:ignore => ['two', 'four']).should_not include(taggable4)
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should accept symbols as ignored tags" do
|
217
|
+
taggable1.find_related_tags(:ignore => :two).should_not include(taggable2)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
188
221
|
context "Inherited Models" do
|
189
222
|
before do
|
190
223
|
@taggable1 = InheritingTaggableModel.create!(:name => "InheritingTaggable 1")
|
@@ -84,8 +84,8 @@ describe ActsAsTaggableOn::TagList do
|
|
84
84
|
it "should lowercase if force_lowercase is set to true" do
|
85
85
|
ActsAsTaggableOn.force_lowercase = true
|
86
86
|
|
87
|
-
tag_list = ActsAsTaggableOn::TagList.new("aweSomE","RaDicaL")
|
88
|
-
tag_list.to_s.should == "awesome, radical"
|
87
|
+
tag_list = ActsAsTaggableOn::TagList.new("aweSomE","RaDicaL","Entrée")
|
88
|
+
tag_list.to_s.should == "awesome, radical, entrée"
|
89
89
|
|
90
90
|
ActsAsTaggableOn.force_lowercase = false
|
91
91
|
end
|
@@ -150,4 +150,63 @@ describe ActsAsTaggableOn::Tag do
|
|
150
150
|
|
151
151
|
end
|
152
152
|
|
153
|
-
|
153
|
+
describe "when using strict_case_match" do
|
154
|
+
before do
|
155
|
+
ActsAsTaggableOn.strict_case_match = true
|
156
|
+
@tag.name = "awesome"
|
157
|
+
@tag.save!
|
158
|
+
end
|
159
|
+
|
160
|
+
after do
|
161
|
+
ActsAsTaggableOn.strict_case_match = false
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should find by name" do
|
165
|
+
ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("awesome").should == @tag
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should find by name case sensitively" do
|
169
|
+
expect {
|
170
|
+
ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("AWESOME")
|
171
|
+
}.to change(ActsAsTaggableOn::Tag, :count)
|
172
|
+
|
173
|
+
ActsAsTaggableOn::Tag.last.name.should == "AWESOME"
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should have a named_scope named(something) that matches exactly" do
|
177
|
+
uppercase_tag = ActsAsTaggableOn::Tag.create(:name => "Cool")
|
178
|
+
@tag.name = "cool"
|
179
|
+
@tag.save!
|
180
|
+
|
181
|
+
ActsAsTaggableOn::Tag.named('cool').should include(@tag)
|
182
|
+
ActsAsTaggableOn::Tag.named('cool').should_not include(uppercase_tag)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "name uniqeness validation" do
|
187
|
+
let(:duplicate_tag) { ActsAsTaggableOn::Tag.new(:name => 'ror') }
|
188
|
+
|
189
|
+
before { ActsAsTaggableOn::Tag.create(:name => 'ror') }
|
190
|
+
|
191
|
+
context "when don't need unique names" do
|
192
|
+
it "should not run uniqueness validation" do
|
193
|
+
duplicate_tag.stub(:validates_name_uniqueness?).and_return(false)
|
194
|
+
duplicate_tag.save
|
195
|
+
duplicate_tag.should be_persisted
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
context "when do need unique names" do
|
200
|
+
it "should run uniqueness validation" do
|
201
|
+
duplicate_tag.should_not be_valid
|
202
|
+
end
|
203
|
+
|
204
|
+
it "add error to name" do
|
205
|
+
duplicate_tag.save
|
206
|
+
|
207
|
+
duplicate_tag.should have(1).errors
|
208
|
+
duplicate_tag.errors.messages[:name].should include('has already been taken')
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
@@ -134,6 +134,16 @@ describe "Taggable" do
|
|
134
134
|
@taggable.tag_counts_on(:tags).length.should == 2
|
135
135
|
end
|
136
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
|
+
|
137
147
|
it "should return [] right after create" do
|
138
148
|
blank_taggable = TaggableModel.new(:name => "Bob Jones")
|
139
149
|
blank_taggable.tag_list.should == []
|
@@ -242,6 +252,15 @@ describe "Taggable" do
|
|
242
252
|
TaggableModel.all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby
|
243
253
|
end
|
244
254
|
|
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
|
+
|
245
264
|
it "should be able to use named scopes to chain tag finds by any tags by context" do
|
246
265
|
bob = TaggableModel.create(:name => "Bob", :need_list => "rails", :offering_list => "c++")
|
247
266
|
frank = TaggableModel.create(:name => "Frank", :need_list => "css", :offering_list => "css")
|
@@ -273,6 +292,14 @@ describe "Taggable" do
|
|
273
292
|
TaggableModel.tagged_with("ruby").all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby
|
274
293
|
end
|
275
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
|
+
|
276
303
|
it 'should only return tag counts for the available scope' do
|
277
304
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
278
305
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
@@ -288,6 +315,21 @@ describe "Taggable" do
|
|
288
315
|
TaggableModel.tagged_with('rails').scoped(:joins => [:untaggable_models]).all_tag_counts.should have(2).items
|
289
316
|
end
|
290
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
|
+
|
291
333
|
it "should be able to set a custom tag context list" do
|
292
334
|
bob = TaggableModel.create(:name => "Bob")
|
293
335
|
bob.set_tag_list_on(:rotors, "spinning, jumping")
|
@@ -456,6 +498,17 @@ describe "Taggable" do
|
|
456
498
|
TaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso fork spoon)
|
457
499
|
end
|
458
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
|
+
|
459
512
|
it 'should store same tag without validation conflict' do
|
460
513
|
@taggable.tag_list = 'one'
|
461
514
|
@taggable.save!
|
@@ -492,6 +545,16 @@ describe "Taggable" do
|
|
492
545
|
@taggable.tag_counts_on(:tags).length.should == 2
|
493
546
|
end
|
494
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
|
+
|
495
558
|
it "should be able to create tags" do
|
496
559
|
@taggable.skill_list = "ruby, rails, css"
|
497
560
|
@taggable.instance_variable_get("@skill_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
|
@@ -538,6 +601,12 @@ describe "Taggable" do
|
|
538
601
|
@taggable.changes.should == {}
|
539
602
|
end
|
540
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
|
541
610
|
end
|
542
611
|
|
543
612
|
|