acts-as-taggable-on 3.1.1 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +9 -7
- data/Appraisals +13 -8
- data/CHANGELOG.md +27 -7
- data/Gemfile +1 -2
- data/README.md +36 -19
- data/Rakefile +5 -17
- data/UPGRADING.md +6 -0
- data/acts-as-taggable-on.gemspec +15 -15
- data/db/migrate/1_acts_as_taggable_on_migration.rb +3 -3
- data/db/migrate/2_add_missing_unique_indices.rb +3 -5
- data/db/migrate/3_add_taggings_counter_cache_to_tags.rb +1 -1
- data/gemfiles/activerecord_3.2.gemfile +15 -0
- data/gemfiles/activerecord_4.0.gemfile +15 -0
- data/gemfiles/activerecord_4.1.gemfile +15 -0
- data/gemfiles/activerecord_edge.gemfile +16 -0
- data/lib/acts-as-taggable-on.rb +23 -21
- data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +2 -4
- data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +29 -20
- data/lib/acts_as_taggable_on/acts_as_taggable_on/compatibility.rb +11 -10
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +103 -85
- data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +5 -12
- data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +11 -11
- data/lib/acts_as_taggable_on/engine.rb +0 -1
- data/lib/acts_as_taggable_on/tag.rb +24 -19
- data/lib/acts_as_taggable_on/tag_list.rb +97 -22
- data/lib/acts_as_taggable_on/taggable.rb +26 -30
- data/lib/acts_as_taggable_on/tagger.rb +30 -18
- data/lib/acts_as_taggable_on/tagging.rb +7 -8
- data/lib/acts_as_taggable_on/tags_helper.rb +1 -1
- data/lib/acts_as_taggable_on/utils.rb +57 -35
- data/lib/acts_as_taggable_on/version.rb +1 -1
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +133 -138
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +55 -58
- data/spec/acts_as_taggable_on/caching_spec.rb +34 -35
- data/spec/acts_as_taggable_on/related_spec.rb +59 -113
- data/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +118 -95
- data/spec/acts_as_taggable_on/tag_list_spec.rb +89 -57
- data/spec/acts_as_taggable_on/tag_spec.rb +129 -116
- data/spec/acts_as_taggable_on/taggable_spec.rb +539 -352
- data/spec/acts_as_taggable_on/tagger_spec.rb +81 -78
- data/spec/acts_as_taggable_on/tagging_spec.rb +13 -14
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +25 -25
- data/spec/acts_as_taggable_on/utils_spec.rb +7 -13
- data/spec/internal/app/models/altered_inheriting_taggable_model.rb +3 -0
- data/spec/internal/app/models/cached_model.rb +3 -0
- data/spec/internal/app/models/cached_model_with_array.rb +5 -0
- data/spec/internal/app/models/company.rb +15 -0
- data/spec/internal/app/models/inheriting_taggable_model.rb +2 -0
- data/spec/internal/app/models/market.rb +2 -0
- data/spec/{models.rb → internal/app/models/models.rb} +34 -2
- data/spec/internal/app/models/non_standard_id_taggable_model.rb +8 -0
- data/spec/internal/app/models/ordered_taggable_model.rb +4 -0
- data/spec/internal/app/models/other_cached_model.rb +3 -0
- data/spec/internal/app/models/other_taggable_model.rb +4 -0
- data/spec/internal/app/models/student.rb +2 -0
- data/spec/internal/app/models/taggable_model.rb +13 -0
- data/spec/internal/app/models/untaggable_model.rb +3 -0
- data/spec/internal/app/models/user.rb +3 -0
- data/spec/{database.yml.sample → internal/config/database.yml.sample} +2 -2
- data/spec/internal/db/schema.rb +97 -0
- data/spec/schema.rb +11 -0
- data/spec/spec_helper.rb +9 -62
- data/spec/support/array.rb +9 -0
- data/spec/support/database.rb +42 -0
- data/spec/support/database_cleaner.rb +21 -0
- metadata +105 -43
- data/gemfiles/rails_3.2.gemfile +0 -7
- data/gemfiles/rails_4.0.gemfile +0 -7
- data/gemfiles/rails_4.1.gemfile +0 -7
- data/gemfiles/rails_edge.gemfile +0 -7
- data/spec/bm.rb +0 -52
|
@@ -1,622 +1,738 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
require 'spec_helper'
|
|
3
3
|
|
|
4
|
-
describe
|
|
4
|
+
describe 'Taggable To Preserve Order' do
|
|
5
5
|
before(:each) do
|
|
6
|
-
|
|
7
|
-
@taggable = OrderedTaggableModel.new(:name => "Bob Jones")
|
|
6
|
+
@taggable = OrderedTaggableModel.new(name: 'Bob Jones')
|
|
8
7
|
end
|
|
9
8
|
|
|
10
|
-
it "should have tag types" do
|
|
11
|
-
[:tags, :colours].each do |type|
|
|
12
|
-
OrderedTaggableModel.tag_types.should include type
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
@taggable.tag_types.should == OrderedTaggableModel.tag_types
|
|
16
|
-
end
|
|
17
9
|
|
|
18
|
-
it
|
|
10
|
+
it 'should have tag associations' do
|
|
19
11
|
[:tags, :colours].each do |type|
|
|
20
|
-
@taggable.respond_to?(type).
|
|
21
|
-
@taggable.respond_to?("#{type.to_s.singularize}_taggings").
|
|
12
|
+
expect(@taggable.respond_to?(type)).to be_truthy
|
|
13
|
+
expect(@taggable.respond_to?("#{type.to_s.singularize}_taggings")).to be_truthy
|
|
22
14
|
end
|
|
23
15
|
end
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
# [:tags, :colours].each do |type|
|
|
27
|
-
# OrderedTaggableModel.reflect_on_association(type).options[:order].should include('id')
|
|
28
|
-
# OrderedTaggableModel.reflect_on_association("#{type.to_s.singularize}_taggings".to_sym).options[:order].should include('id')
|
|
29
|
-
# end
|
|
30
|
-
# end
|
|
31
|
-
|
|
32
|
-
it "should have tag methods" do
|
|
17
|
+
it 'should have tag methods' do
|
|
33
18
|
[:tags, :colours].each do |type|
|
|
34
|
-
@taggable.respond_to?("#{type.to_s.singularize}_list").
|
|
35
|
-
@taggable.respond_to?("#{type.to_s.singularize}_list=").
|
|
36
|
-
@taggable.respond_to?("all_#{type
|
|
19
|
+
expect(@taggable.respond_to?("#{type.to_s.singularize}_list")).to be_truthy
|
|
20
|
+
expect(@taggable.respond_to?("#{type.to_s.singularize}_list=")).to be_truthy
|
|
21
|
+
expect(@taggable.respond_to?("all_#{type}_list")).to be_truthy
|
|
37
22
|
end
|
|
38
23
|
end
|
|
39
24
|
|
|
40
|
-
it
|
|
25
|
+
it 'should return tag list in the order the tags were created' do
|
|
41
26
|
# create
|
|
42
|
-
@taggable.tag_list =
|
|
43
|
-
@taggable.instance_variable_get(
|
|
27
|
+
@taggable.tag_list = 'rails, ruby, css'
|
|
28
|
+
expect(@taggable.instance_variable_get('@tag_list').instance_of?(ActsAsTaggableOn::TagList)).to be_truthy
|
|
44
29
|
|
|
45
|
-
|
|
30
|
+
expect(-> {
|
|
46
31
|
@taggable.save
|
|
47
|
-
}.
|
|
32
|
+
}).to change(ActsAsTaggableOn::Tag, :count).by(3)
|
|
48
33
|
|
|
49
34
|
@taggable.reload
|
|
50
|
-
@taggable.tag_list.
|
|
35
|
+
expect(@taggable.tag_list).to eq(%w(rails ruby css))
|
|
51
36
|
|
|
52
37
|
# update
|
|
53
|
-
@taggable.tag_list =
|
|
38
|
+
@taggable.tag_list = 'pow, ruby, rails'
|
|
54
39
|
@taggable.save
|
|
55
40
|
|
|
56
41
|
@taggable.reload
|
|
57
|
-
@taggable.tag_list.
|
|
42
|
+
expect(@taggable.tag_list).to eq(%w(pow ruby rails))
|
|
58
43
|
|
|
59
44
|
# update with no change
|
|
60
|
-
@taggable.tag_list =
|
|
45
|
+
@taggable.tag_list = 'pow, ruby, rails'
|
|
61
46
|
@taggable.save
|
|
62
47
|
|
|
63
48
|
@taggable.reload
|
|
64
|
-
@taggable.tag_list.
|
|
49
|
+
expect(@taggable.tag_list).to eq(%w(pow ruby rails))
|
|
65
50
|
|
|
66
51
|
# update to clear tags
|
|
67
|
-
@taggable.tag_list =
|
|
52
|
+
@taggable.tag_list = ''
|
|
68
53
|
@taggable.save
|
|
69
54
|
|
|
70
55
|
@taggable.reload
|
|
71
|
-
@taggable.tag_list.
|
|
56
|
+
expect(@taggable.tag_list).to be_empty
|
|
72
57
|
end
|
|
73
58
|
|
|
74
|
-
it
|
|
59
|
+
it 'should return tag objects in the order the tags were created' do
|
|
75
60
|
# create
|
|
76
|
-
@taggable.tag_list =
|
|
77
|
-
@taggable.instance_variable_get(
|
|
61
|
+
@taggable.tag_list = 'pow, ruby, rails'
|
|
62
|
+
expect(@taggable.instance_variable_get('@tag_list').instance_of?(ActsAsTaggableOn::TagList)).to be_truthy
|
|
78
63
|
|
|
79
|
-
|
|
64
|
+
expect(-> {
|
|
80
65
|
@taggable.save
|
|
81
|
-
}.
|
|
66
|
+
}).to change(ActsAsTaggableOn::Tag, :count).by(3)
|
|
82
67
|
|
|
83
68
|
@taggable.reload
|
|
84
|
-
@taggable.tags.map{|t| t.name}.
|
|
69
|
+
expect(@taggable.tags.map { |t| t.name }).to eq(%w(pow ruby rails))
|
|
85
70
|
|
|
86
71
|
# update
|
|
87
|
-
@taggable.tag_list =
|
|
72
|
+
@taggable.tag_list = 'rails, ruby, css, pow'
|
|
88
73
|
@taggable.save
|
|
89
74
|
|
|
90
75
|
@taggable.reload
|
|
91
|
-
@taggable.tags.map{|t| t.name}.
|
|
76
|
+
expect(@taggable.tags.map { |t| t.name }).to eq(%w(rails ruby css pow))
|
|
92
77
|
end
|
|
93
78
|
|
|
94
|
-
it
|
|
79
|
+
it 'should return tag objects in tagging id order' do
|
|
95
80
|
# create
|
|
96
|
-
@taggable.tag_list =
|
|
81
|
+
@taggable.tag_list = 'pow, ruby, rails'
|
|
97
82
|
@taggable.save
|
|
98
83
|
|
|
99
84
|
@taggable.reload
|
|
100
|
-
ids = @taggable.tags.map{|t| t.taggings.first.id}
|
|
101
|
-
ids.
|
|
85
|
+
ids = @taggable.tags.map { |t| t.taggings.first.id }
|
|
86
|
+
expect(ids).to eq(ids.sort)
|
|
102
87
|
|
|
103
88
|
# update
|
|
104
|
-
@taggable.tag_list =
|
|
89
|
+
@taggable.tag_list = 'rails, ruby, css, pow'
|
|
105
90
|
@taggable.save
|
|
106
91
|
|
|
107
92
|
@taggable.reload
|
|
108
|
-
ids = @taggable.tags.map{|t| t.taggings.first.id}
|
|
109
|
-
ids.
|
|
93
|
+
ids = @taggable.tags.map { |t| t.taggings.first.id }
|
|
94
|
+
expect(ids).to eq(ids.sort)
|
|
110
95
|
end
|
|
111
96
|
end
|
|
112
97
|
|
|
113
|
-
describe
|
|
98
|
+
describe 'Taggable' do
|
|
114
99
|
before(:each) do
|
|
115
|
-
|
|
116
|
-
@
|
|
117
|
-
@taggables = [@taggable, TaggableModel.new(:name => "John Doe")]
|
|
100
|
+
@taggable = TaggableModel.new(name: 'Bob Jones')
|
|
101
|
+
@taggables = [@taggable, TaggableModel.new(name: 'John Doe')]
|
|
118
102
|
end
|
|
119
103
|
|
|
120
|
-
it
|
|
104
|
+
it 'should have tag types' do
|
|
121
105
|
[:tags, :languages, :skills, :needs, :offerings].each do |type|
|
|
122
|
-
TaggableModel.tag_types.
|
|
106
|
+
expect(TaggableModel.tag_types).to include type
|
|
123
107
|
end
|
|
124
108
|
|
|
125
|
-
@taggable.tag_types.
|
|
109
|
+
expect(@taggable.tag_types).to eq(TaggableModel.tag_types)
|
|
126
110
|
end
|
|
127
111
|
|
|
128
|
-
it
|
|
129
|
-
TaggableModel.tag_counts_on(:tags).
|
|
112
|
+
it 'should have tag_counts_on' do
|
|
113
|
+
expect(TaggableModel.tag_counts_on(:tags)).to be_empty
|
|
130
114
|
|
|
131
|
-
@taggable.tag_list =
|
|
115
|
+
@taggable.tag_list = %w(awesome epic)
|
|
132
116
|
@taggable.save
|
|
133
117
|
|
|
134
|
-
TaggableModel.tag_counts_on(:tags).length.
|
|
135
|
-
@taggable.tag_counts_on(:tags).length.
|
|
118
|
+
expect(TaggableModel.tag_counts_on(:tags).length).to eq(2)
|
|
119
|
+
expect(@taggable.tag_counts_on(:tags).length).to eq(2)
|
|
136
120
|
end
|
|
137
121
|
|
|
138
|
-
it
|
|
139
|
-
TaggableModel.tags_on(:tags).
|
|
122
|
+
it 'should have tags_on' do
|
|
123
|
+
expect(TaggableModel.tags_on(:tags)).to be_empty
|
|
140
124
|
|
|
141
|
-
@taggable.tag_list =
|
|
125
|
+
@taggable.tag_list = %w(awesome epic)
|
|
142
126
|
@taggable.save
|
|
143
127
|
|
|
144
|
-
TaggableModel.tags_on(:tags).length.
|
|
145
|
-
@taggable.tags_on(:tags).length.
|
|
128
|
+
expect(TaggableModel.tags_on(:tags).length).to eq(2)
|
|
129
|
+
expect(@taggable.tags_on(:tags).length).to eq(2)
|
|
146
130
|
end
|
|
147
131
|
|
|
148
|
-
it
|
|
149
|
-
blank_taggable = TaggableModel.new(:
|
|
150
|
-
blank_taggable.tag_list.
|
|
132
|
+
it 'should return [] right after create' do
|
|
133
|
+
blank_taggable = TaggableModel.new(name: 'Bob Jones')
|
|
134
|
+
expect(blank_taggable.tag_list).to be_empty
|
|
151
135
|
end
|
|
152
136
|
|
|
153
|
-
it
|
|
154
|
-
@taggable.skill_list =
|
|
155
|
-
@taggable.instance_variable_get(
|
|
137
|
+
it 'should be able to create tags' do
|
|
138
|
+
@taggable.skill_list = 'ruby, rails, css'
|
|
139
|
+
expect(@taggable.instance_variable_get('@skill_list').instance_of?(ActsAsTaggableOn::TagList)).to be_truthy
|
|
156
140
|
|
|
157
|
-
|
|
141
|
+
expect(-> {
|
|
158
142
|
@taggable.save
|
|
159
|
-
}.
|
|
143
|
+
}).to change(ActsAsTaggableOn::Tag, :count).by(3)
|
|
160
144
|
|
|
161
145
|
@taggable.reload
|
|
162
|
-
@taggable.skill_list.sort.
|
|
146
|
+
expect(@taggable.skill_list.sort).to eq(%w(ruby rails css).sort)
|
|
163
147
|
end
|
|
164
148
|
|
|
165
|
-
it
|
|
166
|
-
@taggable.tag_list_on(:test).add(
|
|
167
|
-
@taggable.tag_list_cache_on(:test).
|
|
168
|
-
@taggable.tag_list_on(:test).
|
|
149
|
+
it 'should be able to create tags through the tag list directly' do
|
|
150
|
+
@taggable.tag_list_on(:test).add('hello')
|
|
151
|
+
expect(@taggable.tag_list_cache_on(:test)).to_not be_empty
|
|
152
|
+
expect(@taggable.tag_list_on(:test)).to eq(['hello'])
|
|
169
153
|
|
|
170
154
|
@taggable.save
|
|
171
155
|
@taggable.save_tags
|
|
172
156
|
|
|
173
157
|
@taggable.reload
|
|
174
|
-
@taggable.tag_list_on(:test).
|
|
158
|
+
expect(@taggable.tag_list_on(:test)).to eq(['hello'])
|
|
175
159
|
end
|
|
176
160
|
|
|
177
|
-
it
|
|
178
|
-
@taggable.skill_list =
|
|
179
|
-
@taggable.tag_list =
|
|
161
|
+
it 'should differentiate between contexts' do
|
|
162
|
+
@taggable.skill_list = 'ruby, rails, css'
|
|
163
|
+
@taggable.tag_list = 'ruby, bob, charlie'
|
|
180
164
|
@taggable.save
|
|
181
165
|
@taggable.reload
|
|
182
|
-
@taggable.skill_list.
|
|
183
|
-
@taggable.skill_list.
|
|
166
|
+
expect(@taggable.skill_list).to include('ruby')
|
|
167
|
+
expect(@taggable.skill_list).to_not include('bob')
|
|
184
168
|
end
|
|
185
169
|
|
|
186
|
-
it
|
|
187
|
-
@taggable.skill_list =
|
|
170
|
+
it 'should be able to remove tags through list alone' do
|
|
171
|
+
@taggable.skill_list = 'ruby, rails, css'
|
|
188
172
|
@taggable.save
|
|
189
173
|
@taggable.reload
|
|
190
|
-
@taggable.
|
|
191
|
-
@taggable.skill_list =
|
|
174
|
+
expect(@taggable.skills.count).to eq(3)
|
|
175
|
+
@taggable.skill_list = 'ruby, rails'
|
|
192
176
|
@taggable.save
|
|
193
177
|
@taggable.reload
|
|
194
|
-
@taggable.
|
|
178
|
+
expect(@taggable.skills.count).to eq(2)
|
|
195
179
|
end
|
|
196
180
|
|
|
197
|
-
it
|
|
198
|
-
@taggables[0].tag_list =
|
|
199
|
-
@taggables[1].tag_list =
|
|
200
|
-
@taggables[0].skill_list =
|
|
201
|
-
@taggables[1].skill_list =
|
|
202
|
-
@taggables.each{|taggable| taggable.save}
|
|
181
|
+
it 'should be able to select taggables by subset of tags using ActiveRelation methods' do
|
|
182
|
+
@taggables[0].tag_list = 'bob'
|
|
183
|
+
@taggables[1].tag_list = 'charlie'
|
|
184
|
+
@taggables[0].skill_list = 'ruby'
|
|
185
|
+
@taggables[1].skill_list = 'css'
|
|
186
|
+
@taggables.each { |taggable| taggable.save }
|
|
203
187
|
|
|
204
|
-
@found_taggables_by_tag = TaggableModel.joins(:tags).where(:
|
|
205
|
-
@found_taggables_by_skill = TaggableModel.joins(:skills).where(:
|
|
188
|
+
@found_taggables_by_tag = TaggableModel.joins(:tags).where(tags: {name: ['bob']})
|
|
189
|
+
@found_taggables_by_skill = TaggableModel.joins(:skills).where(tags: {name: ['ruby']})
|
|
206
190
|
|
|
207
|
-
@found_taggables_by_tag.
|
|
208
|
-
@found_taggables_by_tag.
|
|
209
|
-
@found_taggables_by_skill.
|
|
210
|
-
@found_taggables_by_skill.
|
|
191
|
+
expect(@found_taggables_by_tag).to include @taggables[0]
|
|
192
|
+
expect(@found_taggables_by_tag).to_not include @taggables[1]
|
|
193
|
+
expect(@found_taggables_by_skill).to include @taggables[0]
|
|
194
|
+
expect(@found_taggables_by_skill).to_not include @taggables[1]
|
|
211
195
|
end
|
|
212
196
|
|
|
213
|
-
it
|
|
214
|
-
@taggable.skill_list =
|
|
197
|
+
it 'should be able to find by tag' do
|
|
198
|
+
@taggable.skill_list = 'ruby, rails, css'
|
|
215
199
|
@taggable.save
|
|
216
200
|
|
|
217
|
-
TaggableModel.tagged_with(
|
|
201
|
+
expect(TaggableModel.tagged_with('ruby').first).to eq(@taggable)
|
|
218
202
|
end
|
|
219
203
|
|
|
220
|
-
it
|
|
221
|
-
@taggable.skill_list =
|
|
204
|
+
it 'should be able to get a count with find by tag when using a group by' do
|
|
205
|
+
@taggable.skill_list = 'ruby'
|
|
222
206
|
@taggable.save
|
|
223
207
|
|
|
224
|
-
expect(TaggableModel.tagged_with(
|
|
208
|
+
expect(TaggableModel.tagged_with('ruby').group(:created_at).count.count).to eq(1)
|
|
225
209
|
end
|
|
226
210
|
|
|
227
|
-
it "
|
|
228
|
-
@taggable.skill_list =
|
|
229
|
-
@taggable.tag_list = "bob, charlie"
|
|
211
|
+
it "shouldn't generate a query with DISTINCT by default" do
|
|
212
|
+
@taggable.skill_list = 'ruby, rails, css'
|
|
230
213
|
@taggable.save
|
|
231
214
|
|
|
232
|
-
TaggableModel.tagged_with(
|
|
233
|
-
TaggableModel.tagged_with("ruby, css").first.should == @taggable
|
|
234
|
-
TaggableModel.tagged_with("bob", :on => :skills).first.should_not == @taggable
|
|
235
|
-
TaggableModel.tagged_with("bob", :on => :tags).first.should == @taggable
|
|
215
|
+
expect(TaggableModel.tagged_with('ruby').to_sql).to_not match /DISTINCT/
|
|
236
216
|
end
|
|
237
217
|
|
|
238
|
-
it
|
|
239
|
-
|
|
240
|
-
|
|
218
|
+
it 'should be able to find by tag with context' do
|
|
219
|
+
@taggable.skill_list = 'ruby, rails, css'
|
|
220
|
+
@taggable.tag_list = 'bob, charlie'
|
|
221
|
+
@taggable.save
|
|
241
222
|
|
|
242
|
-
|
|
243
|
-
TaggableModel.tagged_with(
|
|
223
|
+
expect(TaggableModel.tagged_with('ruby').first).to eq(@taggable)
|
|
224
|
+
expect(TaggableModel.tagged_with('ruby, css').first).to eq(@taggable)
|
|
225
|
+
expect(TaggableModel.tagged_with('bob', on: :skills).first).to_not eq(@taggable)
|
|
226
|
+
expect(TaggableModel.tagged_with('bob', on: :tags).first).to eq(@taggable)
|
|
244
227
|
end
|
|
245
228
|
|
|
246
|
-
|
|
247
|
-
|
|
229
|
+
it 'should not care about case' do
|
|
230
|
+
TaggableModel.create(name: 'Bob', tag_list: 'ruby')
|
|
231
|
+
TaggableModel.create(name: 'Frank', tag_list: 'Ruby')
|
|
232
|
+
|
|
233
|
+
expect(ActsAsTaggableOn::Tag.all.size).to eq(1)
|
|
234
|
+
expect(TaggableModel.tagged_with('ruby').to_a).to eq(TaggableModel.tagged_with('Ruby').to_a)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'should be able to find by tags with other joins in the query' do
|
|
238
|
+
@taggable.skill_list = 'ruby, rails, css'
|
|
239
|
+
@taggable.tag_list = 'bob, charlie'
|
|
240
|
+
@taggable.save
|
|
241
|
+
|
|
242
|
+
expect(TaggableModel.group(:created_at).tagged_with(['bob', 'css'], :any => true).first).to eq(@taggable)
|
|
243
|
+
|
|
244
|
+
bob = TaggableModel.create(:name => 'Bob', :tag_list => 'ruby, rails, css')
|
|
245
|
+
frank = TaggableModel.create(:name => 'Frank', :tag_list => 'ruby, rails')
|
|
246
|
+
charlie = TaggableModel.create(:name => 'Charlie', :skill_list => 'ruby, java')
|
|
247
|
+
|
|
248
|
+
# Test for explicit distinct in select
|
|
249
|
+
bob.untaggable_models.create!
|
|
250
|
+
frank.untaggable_models.create!
|
|
251
|
+
charlie.untaggable_models.create!
|
|
252
|
+
|
|
253
|
+
expect(TaggableModel.select('distinct(taggable_models.id), taggable_models.*').joins(:untaggable_models).tagged_with(['css', 'java'], :any => true).to_a.sort).to eq([bob, charlie].sort)
|
|
254
|
+
|
|
255
|
+
expect(TaggableModel.select('distinct(taggable_models.id), taggable_models.*').joins(:untaggable_models).tagged_with(['rails', 'ruby'], :any => false).to_a.sort).to eq([bob, frank].sort)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
unless ActsAsTaggableOn::Utils.using_sqlite?
|
|
259
|
+
it 'should not care about case for unicode names' do
|
|
248
260
|
ActsAsTaggableOn.strict_case_match = false
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
katia = TaggableModel.create(:name => "Katia", :tag_list => "ПРИВЕТ")
|
|
261
|
+
TaggableModel.create(name: 'Anya', tag_list: 'ПРИВЕТ')
|
|
262
|
+
TaggableModel.create(name: 'Igor', tag_list: 'привет')
|
|
263
|
+
TaggableModel.create(name: 'Katia', tag_list: 'ПРИВЕТ')
|
|
253
264
|
|
|
254
|
-
ActsAsTaggableOn::Tag.all.size.
|
|
255
|
-
TaggableModel.tagged_with(
|
|
265
|
+
expect(ActsAsTaggableOn::Tag.all.size).to eq(1)
|
|
266
|
+
expect(TaggableModel.tagged_with('привет').to_a).to eq(TaggableModel.tagged_with('ПРИВЕТ').to_a)
|
|
256
267
|
end
|
|
257
268
|
end
|
|
258
269
|
|
|
259
|
-
|
|
270
|
+
context 'should be able to create and find tags in languages without capitalization :' do
|
|
260
271
|
ActsAsTaggableOn.strict_case_match = false
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
272
|
+
{
|
|
273
|
+
japanese: {name: 'Chihiro', tag_list: '日本の'},
|
|
274
|
+
hebrew: {name: 'Salim', tag_list: 'עברית'},
|
|
275
|
+
chinese: {name: 'Ieie', tag_list: '中国的'},
|
|
276
|
+
arabic: {name: 'Yasser', tag_list: 'العربية'},
|
|
277
|
+
emo: {name: 'Emo', tag_list: '✏'}
|
|
278
|
+
}.each do |language, values|
|
|
279
|
+
|
|
280
|
+
it language do
|
|
281
|
+
TaggableModel.create(values)
|
|
282
|
+
expect(TaggableModel.tagged_with(values[:tag_list]).count).to eq(1)
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
273
286
|
|
|
274
|
-
it
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
TaggableModel.tag_counts.
|
|
279
|
-
TaggableModel.skill_counts.
|
|
287
|
+
it 'should be able to get tag counts on model as a whole' do
|
|
288
|
+
TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
|
|
289
|
+
TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
|
|
290
|
+
TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
|
|
291
|
+
expect(TaggableModel.tag_counts).to_not be_empty
|
|
292
|
+
expect(TaggableModel.skill_counts).to_not be_empty
|
|
280
293
|
end
|
|
281
294
|
|
|
282
|
-
it
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
295
|
+
it 'should be able to get all tag counts on model as whole' do
|
|
296
|
+
TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
|
|
297
|
+
TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
|
|
298
|
+
TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
|
|
286
299
|
|
|
287
|
-
TaggableModel.all_tag_counts.
|
|
288
|
-
TaggableModel.all_tag_counts(:
|
|
300
|
+
expect(TaggableModel.all_tag_counts).to_not be_empty
|
|
301
|
+
expect(TaggableModel.all_tag_counts(order: 'tags.id').first.count).to eq(3) # ruby
|
|
289
302
|
end
|
|
290
303
|
|
|
291
|
-
it
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
304
|
+
it 'should be able to get all tags on model as whole' do
|
|
305
|
+
TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
|
|
306
|
+
TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
|
|
307
|
+
TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
|
|
295
308
|
|
|
296
|
-
TaggableModel.all_tags.
|
|
297
|
-
TaggableModel.all_tags(:
|
|
309
|
+
expect(TaggableModel.all_tags).to_not be_empty
|
|
310
|
+
expect(TaggableModel.all_tags(order: 'tags.id').first.name).to eq('ruby')
|
|
298
311
|
end
|
|
299
312
|
|
|
300
|
-
it
|
|
301
|
-
bob
|
|
302
|
-
|
|
303
|
-
|
|
313
|
+
it 'should be able to use named scopes to chain tag finds by any tags by context' do
|
|
314
|
+
bob = TaggableModel.create(name: 'Bob', need_list: 'rails', offering_list: 'c++')
|
|
315
|
+
TaggableModel.create(name: 'Frank', need_list: 'css', offering_list: 'css')
|
|
316
|
+
TaggableModel.create(name: 'Steve', need_list: 'c++', offering_list: 'java')
|
|
304
317
|
|
|
305
318
|
# Let's only find those who need rails or css and are offering c++ or java
|
|
306
|
-
TaggableModel.tagged_with(['rails, css'], :
|
|
319
|
+
expect(TaggableModel.tagged_with(['rails, css'], on: :needs, any: true).tagged_with(['c++', 'java'], on: :offerings, any: true).to_a).to eq([bob])
|
|
307
320
|
end
|
|
308
321
|
|
|
309
|
-
it
|
|
310
|
-
TaggableModel.create(:
|
|
311
|
-
TaggableModel.tagged_with(
|
|
322
|
+
it 'should not return read-only records' do
|
|
323
|
+
TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
|
|
324
|
+
expect(TaggableModel.tagged_with('ruby').first).to_not be_readonly
|
|
312
325
|
end
|
|
313
326
|
|
|
314
|
-
it
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
327
|
+
it 'should be able to get scoped tag counts' do
|
|
328
|
+
TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
|
|
329
|
+
TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
|
|
330
|
+
TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
|
|
318
331
|
|
|
319
|
-
TaggableModel.tagged_with(
|
|
320
|
-
TaggableModel.tagged_with(
|
|
332
|
+
expect(TaggableModel.tagged_with('ruby').tag_counts(order: 'tags.id').first.count).to eq(2) # ruby
|
|
333
|
+
expect(TaggableModel.tagged_with('ruby').skill_counts.first.count).to eq(1) # ruby
|
|
321
334
|
end
|
|
322
335
|
|
|
323
|
-
it
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
336
|
+
it 'should be able to get all scoped tag counts' do
|
|
337
|
+
TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
|
|
338
|
+
TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
|
|
339
|
+
TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
|
|
327
340
|
|
|
328
|
-
TaggableModel.tagged_with(
|
|
341
|
+
expect(TaggableModel.tagged_with('ruby').all_tag_counts(order: 'tags.id').first.count).to eq(3) # ruby
|
|
329
342
|
end
|
|
330
343
|
|
|
331
|
-
it
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
344
|
+
it 'should be able to get all scoped tags' do
|
|
345
|
+
TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
|
|
346
|
+
TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
|
|
347
|
+
TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
|
|
335
348
|
|
|
336
|
-
TaggableModel.tagged_with(
|
|
349
|
+
expect(TaggableModel.tagged_with('ruby').all_tags(order: 'tags.id').first.name).to eq('ruby')
|
|
337
350
|
end
|
|
338
351
|
|
|
339
352
|
it 'should only return tag counts for the available scope' do
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
353
|
+
frank = TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
|
|
354
|
+
TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
|
|
355
|
+
TaggableModel.create(name: 'Charlie', skill_list: 'ruby, java')
|
|
343
356
|
|
|
344
|
-
TaggableModel.tagged_with('rails').all_tag_counts.
|
|
345
|
-
TaggableModel.tagged_with('rails').all_tag_counts.any? { |tag| tag.name == 'java' }.
|
|
357
|
+
expect(TaggableModel.tagged_with('rails').all_tag_counts.size).to eq(3)
|
|
358
|
+
expect(TaggableModel.tagged_with('rails').all_tag_counts.any? { |tag| tag.name == 'java' }).to be_falsy
|
|
346
359
|
|
|
347
360
|
# Test specific join syntaxes:
|
|
348
361
|
frank.untaggable_models.create!
|
|
349
|
-
TaggableModel.tagged_with('rails').joins(:untaggable_models).all_tag_counts.
|
|
350
|
-
TaggableModel.tagged_with('rails').joins(:
|
|
351
|
-
TaggableModel.tagged_with('rails').joins([:untaggable_models]).all_tag_counts.
|
|
362
|
+
expect(TaggableModel.tagged_with('rails').joins(:untaggable_models).all_tag_counts.size).to eq(2)
|
|
363
|
+
expect(TaggableModel.tagged_with('rails').joins(untaggable_models: :taggable_model).all_tag_counts.size).to eq(2)
|
|
364
|
+
expect(TaggableModel.tagged_with('rails').joins([:untaggable_models]).all_tag_counts.size).to eq(2)
|
|
352
365
|
end
|
|
353
366
|
|
|
354
367
|
it 'should only return tags for the available scope' do
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
368
|
+
frank = TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
|
|
369
|
+
TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
|
|
370
|
+
TaggableModel.create(name: 'Charlie', skill_list: 'ruby, java')
|
|
358
371
|
|
|
359
|
-
TaggableModel.tagged_with('rails').all_tags.
|
|
360
|
-
TaggableModel.tagged_with('rails').all_tags.any? { |tag| tag.name == 'java' }.
|
|
372
|
+
expect(TaggableModel.tagged_with('rails').all_tags.count).to eq(3)
|
|
373
|
+
expect(TaggableModel.tagged_with('rails').all_tags.any? { |tag| tag.name == 'java' }).to be_falsy
|
|
361
374
|
|
|
362
375
|
# Test specific join syntaxes:
|
|
363
376
|
frank.untaggable_models.create!
|
|
364
|
-
TaggableModel.tagged_with('rails').joins(:untaggable_models).all_tags.
|
|
365
|
-
TaggableModel.tagged_with('rails').joins(
|
|
366
|
-
TaggableModel.tagged_with('rails').joins([:untaggable_models]).all_tags.
|
|
377
|
+
expect(TaggableModel.tagged_with('rails').joins(:untaggable_models).all_tags.size).to eq(2)
|
|
378
|
+
expect(TaggableModel.tagged_with('rails').joins(untaggable_models: :taggable_model).all_tags.size).to eq(2)
|
|
379
|
+
expect(TaggableModel.tagged_with('rails').joins([:untaggable_models]).all_tags.size).to eq(2)
|
|
367
380
|
end
|
|
368
381
|
|
|
369
|
-
it
|
|
370
|
-
bob = TaggableModel.create(:
|
|
371
|
-
bob.set_tag_list_on(:rotors,
|
|
372
|
-
bob.tag_list_on(:rotors).
|
|
382
|
+
it 'should be able to set a custom tag context list' do
|
|
383
|
+
bob = TaggableModel.create(name: 'Bob')
|
|
384
|
+
bob.set_tag_list_on(:rotors, 'spinning, jumping')
|
|
385
|
+
expect(bob.tag_list_on(:rotors)).to eq(%w(spinning jumping))
|
|
373
386
|
bob.save
|
|
374
387
|
bob.reload
|
|
375
|
-
bob.tags_on(:rotors).
|
|
388
|
+
expect(bob.tags_on(:rotors)).to_not be_empty
|
|
376
389
|
end
|
|
377
390
|
|
|
378
|
-
it
|
|
379
|
-
bob = TaggableModel.create(:
|
|
380
|
-
frank = TaggableModel.create(:
|
|
381
|
-
steve = TaggableModel.create(:
|
|
391
|
+
it 'should be able to find tagged' do
|
|
392
|
+
bob = TaggableModel.create(name: 'Bob', tag_list: 'fitter, happier, more productive', skill_list: 'ruby, rails, css')
|
|
393
|
+
frank = TaggableModel.create(name: 'Frank', tag_list: 'weaker, depressed, inefficient', skill_list: 'ruby, rails, css')
|
|
394
|
+
steve = TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier, more productive', skill_list: 'c++, java, ruby')
|
|
382
395
|
|
|
383
|
-
TaggableModel.tagged_with(
|
|
384
|
-
TaggableModel.tagged_with(
|
|
385
|
-
TaggableModel.tagged_with(
|
|
396
|
+
expect(TaggableModel.tagged_with('ruby', order: 'taggable_models.name').to_a).to eq([bob, frank, steve])
|
|
397
|
+
expect(TaggableModel.tagged_with('ruby, rails', order: 'taggable_models.name').to_a).to eq([bob, frank])
|
|
398
|
+
expect(TaggableModel.tagged_with(%w(ruby rails), order: 'taggable_models.name').to_a).to eq([bob, frank])
|
|
386
399
|
end
|
|
387
400
|
|
|
388
|
-
it
|
|
389
|
-
bob = TaggableModel.create(:
|
|
390
|
-
TaggableModel.tagged_with("'I love the ,comma,'").
|
|
401
|
+
it 'should be able to find tagged with quotation marks' do
|
|
402
|
+
bob = TaggableModel.create(name: 'Bob', tag_list: "fitter, happier, more productive, 'I love the ,comma,'")
|
|
403
|
+
expect(TaggableModel.tagged_with("'I love the ,comma,'")).to include(bob)
|
|
391
404
|
end
|
|
392
405
|
|
|
393
|
-
it
|
|
394
|
-
bob = TaggableModel.create(:
|
|
395
|
-
TaggableModel.tagged_with(
|
|
406
|
+
it 'should be able to find tagged with invalid tags' do
|
|
407
|
+
bob = TaggableModel.create(name: 'Bob', tag_list: 'fitter, happier, more productive')
|
|
408
|
+
expect(TaggableModel.tagged_with('sad, happier')).to_not include(bob)
|
|
396
409
|
end
|
|
397
410
|
|
|
398
|
-
it
|
|
399
|
-
bob = TaggableModel.create(:
|
|
400
|
-
frank = TaggableModel.create(:
|
|
401
|
-
steve = TaggableModel.create(:
|
|
411
|
+
it 'should be able to find tagged with any tag' do
|
|
412
|
+
bob = TaggableModel.create(name: 'Bob', tag_list: 'fitter, happier, more productive', skill_list: 'ruby, rails, css')
|
|
413
|
+
frank = TaggableModel.create(name: 'Frank', tag_list: 'weaker, depressed, inefficient', skill_list: 'ruby, rails, css')
|
|
414
|
+
steve = TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier, more productive', skill_list: 'c++, java, ruby')
|
|
402
415
|
|
|
403
|
-
TaggableModel.tagged_with(
|
|
404
|
-
TaggableModel.tagged_with(
|
|
405
|
-
TaggableModel.tagged_with(
|
|
416
|
+
expect(TaggableModel.tagged_with(%w(ruby java), order: 'taggable_models.name', any: true).to_a).to eq([bob, frank, steve])
|
|
417
|
+
expect(TaggableModel.tagged_with(%w(c++ fitter), order: 'taggable_models.name', any: true).to_a).to eq([bob, steve])
|
|
418
|
+
expect(TaggableModel.tagged_with(%w(depressed css), order: 'taggable_models.name', any: true).to_a).to eq([bob, frank])
|
|
406
419
|
end
|
|
407
420
|
|
|
408
|
-
it
|
|
409
|
-
bob = TaggableModel.create(:
|
|
410
|
-
frank = TaggableModel.create(:
|
|
411
|
-
steve = TaggableModel.create(:
|
|
421
|
+
it 'should be able to order by number of matching tags when matching any' do
|
|
422
|
+
bob = TaggableModel.create(name: 'Bob', tag_list: 'fitter, happier, more productive', skill_list: 'ruby, rails, css')
|
|
423
|
+
frank = TaggableModel.create(name: 'Frank', tag_list: 'weaker, depressed, inefficient', skill_list: 'ruby, rails, css')
|
|
424
|
+
steve = TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier, more productive', skill_list: 'c++, java, ruby')
|
|
412
425
|
|
|
413
|
-
TaggableModel.tagged_with(
|
|
414
|
-
TaggableModel.tagged_with(
|
|
415
|
-
TaggableModel.tagged_with(
|
|
416
|
-
TaggableModel.tagged_with([
|
|
417
|
-
TaggableModel.tagged_with(
|
|
426
|
+
expect(TaggableModel.tagged_with(%w(ruby java), any: true, order_by_matching_tag_count: true, order: 'taggable_models.name').to_a).to eq([steve, bob, frank])
|
|
427
|
+
expect(TaggableModel.tagged_with(%w(c++ fitter), any: true, order_by_matching_tag_count: true, order: 'taggable_models.name').to_a).to eq([steve, bob])
|
|
428
|
+
expect(TaggableModel.tagged_with(%w(depressed css), any: true, order_by_matching_tag_count: true, order: 'taggable_models.name').to_a).to eq([frank, bob])
|
|
429
|
+
expect(TaggableModel.tagged_with(['fitter', 'happier', 'more productive', 'c++', 'java', 'ruby'], any: true, order_by_matching_tag_count: true, order: 'taggable_models.name').to_a).to eq([steve, bob, frank])
|
|
430
|
+
expect(TaggableModel.tagged_with(%w(c++ java ruby fitter), any: true, order_by_matching_tag_count: true, order: 'taggable_models.name').to_a).to eq([steve, bob, frank])
|
|
418
431
|
end
|
|
419
432
|
|
|
420
|
-
context
|
|
421
|
-
it
|
|
422
|
-
bob = TaggableModel.create(:
|
|
423
|
-
frank = TaggableModel.create(:
|
|
424
|
-
steve = TaggableModel.create(:
|
|
425
|
-
jim = TaggableModel.create(:
|
|
426
|
-
|
|
433
|
+
context 'wild: true' do
|
|
434
|
+
it 'should use params as wildcards' do
|
|
435
|
+
bob = TaggableModel.create(name: 'Bob', tag_list: 'bob, tricia')
|
|
436
|
+
frank = TaggableModel.create(name: 'Frank', tag_list: 'bobby, jim')
|
|
437
|
+
steve = TaggableModel.create(name: 'Steve', tag_list: 'john, patricia')
|
|
438
|
+
jim = TaggableModel.create(name: 'Jim', tag_list: 'jim, steve')
|
|
427
439
|
|
|
428
|
-
TaggableModel.tagged_with(
|
|
429
|
-
TaggableModel.tagged_with(
|
|
440
|
+
expect(TaggableModel.tagged_with(%w(bob tricia), wild: true, any: true).to_a.sort_by { |o| o.id }).to eq([bob, frank, steve])
|
|
441
|
+
expect(TaggableModel.tagged_with(%w(bob tricia), wild: true, exclude: true).to_a).to eq([jim])
|
|
430
442
|
end
|
|
431
443
|
end
|
|
432
444
|
|
|
433
|
-
it
|
|
434
|
-
bob = TaggableModel.create(:
|
|
435
|
-
bob.set_tag_list_on(:rotors,
|
|
436
|
-
bob.tag_list_on(:rotors).
|
|
445
|
+
it 'should be able to find tagged on a custom tag context' do
|
|
446
|
+
bob = TaggableModel.create(name: 'Bob')
|
|
447
|
+
bob.set_tag_list_on(:rotors, 'spinning, jumping')
|
|
448
|
+
expect(bob.tag_list_on(:rotors)).to eq(%w(spinning jumping))
|
|
437
449
|
bob.save
|
|
438
450
|
|
|
439
|
-
TaggableModel.tagged_with(
|
|
451
|
+
expect(TaggableModel.tagged_with('spinning', on: :rotors).to_a).to eq([bob])
|
|
440
452
|
end
|
|
441
453
|
|
|
442
|
-
it
|
|
443
|
-
bob = TaggableModel.create(:
|
|
444
|
-
frank = TaggableModel.create(:
|
|
445
|
-
steve = TaggableModel.create(:
|
|
454
|
+
it 'should be able to use named scopes to chain tag finds' do
|
|
455
|
+
bob = TaggableModel.create(name: 'Bob', tag_list: 'fitter, happier, more productive', skill_list: 'ruby, rails, css')
|
|
456
|
+
frank = TaggableModel.create(name: 'Frank', tag_list: 'weaker, depressed, inefficient', skill_list: 'ruby, rails, css')
|
|
457
|
+
steve = TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier, more productive', skill_list: 'c++, java, python')
|
|
446
458
|
|
|
447
459
|
# Let's only find those productive Rails developers
|
|
448
|
-
TaggableModel.tagged_with('rails', :
|
|
449
|
-
TaggableModel.tagged_with('happier', :
|
|
450
|
-
TaggableModel.tagged_with('rails', :
|
|
451
|
-
TaggableModel.tagged_with('rails').tagged_with('happier', :
|
|
460
|
+
expect(TaggableModel.tagged_with('rails', on: :skills, order: 'taggable_models.name').to_a).to eq([bob, frank])
|
|
461
|
+
expect(TaggableModel.tagged_with('happier', on: :tags, order: 'taggable_models.name').to_a).to eq([bob, steve])
|
|
462
|
+
expect(TaggableModel.tagged_with('rails', on: :skills).tagged_with('happier', on: :tags).to_a).to eq([bob])
|
|
463
|
+
expect(TaggableModel.tagged_with('rails').tagged_with('happier', on: :tags).to_a).to eq([bob])
|
|
452
464
|
end
|
|
453
465
|
|
|
454
|
-
it
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
steve = TaggableModel.create(:
|
|
466
|
+
it 'should be able to find tagged with only the matching tags' do
|
|
467
|
+
TaggableModel.create(name: 'Bob', tag_list: 'lazy, happier')
|
|
468
|
+
TaggableModel.create(name: 'Frank', tag_list: 'fitter, happier, inefficient')
|
|
469
|
+
steve = TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier')
|
|
458
470
|
|
|
459
|
-
TaggableModel.tagged_with(
|
|
471
|
+
expect(TaggableModel.tagged_with('fitter, happier', match_all: true).to_a).to eq([steve])
|
|
460
472
|
end
|
|
461
473
|
|
|
462
|
-
it
|
|
463
|
-
|
|
464
|
-
frank = TaggableModel.create(:
|
|
465
|
-
|
|
474
|
+
it 'should be able to find tagged with only the matching tags for a context' do
|
|
475
|
+
TaggableModel.create(name: 'Bob', tag_list: 'lazy, happier', skill_list: 'ruby, rails, css')
|
|
476
|
+
frank = TaggableModel.create(name: 'Frank', tag_list: 'fitter, happier, inefficient', skill_list: 'css')
|
|
477
|
+
TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier', skill_list: 'ruby, rails, css')
|
|
466
478
|
|
|
467
|
-
TaggableModel.tagged_with(
|
|
479
|
+
expect(TaggableModel.tagged_with('css', on: :skills, match_all: true).to_a).to eq([frank])
|
|
468
480
|
end
|
|
469
481
|
|
|
470
|
-
it
|
|
471
|
-
|
|
472
|
-
frank = TaggableModel.create(:
|
|
473
|
-
steve = TaggableModel.create(:
|
|
482
|
+
it 'should be able to find tagged with some excluded tags' do
|
|
483
|
+
TaggableModel.create(name: 'Bob', tag_list: 'happier, lazy')
|
|
484
|
+
frank = TaggableModel.create(name: 'Frank', tag_list: 'happier')
|
|
485
|
+
steve = TaggableModel.create(name: 'Steve', tag_list: 'happier')
|
|
474
486
|
|
|
475
|
-
TaggableModel.tagged_with(
|
|
487
|
+
expect(TaggableModel.tagged_with('lazy', exclude: true)).to include(frank, steve)
|
|
488
|
+
expect(TaggableModel.tagged_with('lazy', exclude: true).size).to eq(2)
|
|
476
489
|
end
|
|
477
490
|
|
|
478
|
-
it
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
TaggableModel.tagged_with([]).should == []
|
|
491
|
+
it 'should return an empty scope for empty tags' do
|
|
492
|
+
['', ' ', nil, []].each do |tag|
|
|
493
|
+
expect(TaggableModel.tagged_with(tag)).to be_empty
|
|
494
|
+
end
|
|
483
495
|
end
|
|
484
496
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
497
|
+
context 'Duplicates' do
|
|
498
|
+
context 'should not create duplicate taggings' do
|
|
499
|
+
let(:bob) { TaggableModel.create(name: 'Bob') }
|
|
500
|
+
context 'case sensitive' do
|
|
501
|
+
it '#add' do
|
|
502
|
+
expect(lambda {
|
|
503
|
+
bob.tag_list.add 'happier'
|
|
504
|
+
bob.tag_list.add 'happier'
|
|
505
|
+
bob.tag_list.add 'happier', 'rich', 'funny'
|
|
506
|
+
bob.save
|
|
507
|
+
}).to change(ActsAsTaggableOn::Tagging, :count).by(3)
|
|
508
|
+
end
|
|
509
|
+
it '#<<' do
|
|
510
|
+
expect(lambda {
|
|
511
|
+
bob.tag_list << 'social'
|
|
512
|
+
bob.tag_list << 'social'
|
|
513
|
+
bob.tag_list << 'social' << 'wow'
|
|
514
|
+
bob.save
|
|
515
|
+
}).to change(ActsAsTaggableOn::Tagging, :count).by(2)
|
|
516
|
+
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
it 'unicode' do
|
|
520
|
+
|
|
521
|
+
expect(lambda {
|
|
522
|
+
bob.tag_list.add 'ПРИВЕТ'
|
|
523
|
+
bob.tag_list.add 'ПРИВЕТ'
|
|
524
|
+
bob.tag_list.add 'ПРИВЕТ', 'ПРИВЕТ'
|
|
525
|
+
bob.save
|
|
526
|
+
}).to change(ActsAsTaggableOn::Tagging, :count).by(1)
|
|
527
|
+
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
it '#=' do
|
|
531
|
+
expect(lambda {
|
|
532
|
+
bob.tag_list = ['Happy', 'Happy']
|
|
533
|
+
bob.save
|
|
534
|
+
}).to change(ActsAsTaggableOn::Tagging, :count).by(1)
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
context 'case insensitive' do
|
|
538
|
+
before(:all) { ActsAsTaggableOn.force_lowercase = true }
|
|
539
|
+
after(:all) { ActsAsTaggableOn.force_lowercase = false }
|
|
540
|
+
|
|
541
|
+
it '#<<' do
|
|
542
|
+
expect(lambda {
|
|
543
|
+
bob.tag_list << 'Alone'
|
|
544
|
+
bob.tag_list << 'AloNe'
|
|
545
|
+
bob.tag_list << 'ALONE' << 'In The dark'
|
|
546
|
+
bob.save
|
|
547
|
+
}).to change(ActsAsTaggableOn::Tagging, :count).by(2)
|
|
548
|
+
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
it '#add' do
|
|
552
|
+
expect(lambda {
|
|
553
|
+
bob.tag_list.add 'forever'
|
|
554
|
+
bob.tag_list.add 'ForEver'
|
|
555
|
+
bob.tag_list.add 'FOREVER', 'ALONE'
|
|
556
|
+
bob.save
|
|
557
|
+
}).to change(ActsAsTaggableOn::Tagging, :count).by(2)
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
it 'unicode' do
|
|
561
|
+
|
|
562
|
+
expect(lambda {
|
|
563
|
+
bob.tag_list.add 'ПРИВЕТ'
|
|
564
|
+
bob.tag_list.add 'привет', 'Привет'
|
|
565
|
+
bob.save
|
|
566
|
+
}).to change(ActsAsTaggableOn::Tagging, :count).by(1)
|
|
567
|
+
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
it '#=' do
|
|
571
|
+
expect(lambda {
|
|
572
|
+
bob.tag_list = ['Happy', 'HAPPY']
|
|
573
|
+
bob.save
|
|
574
|
+
}).to change(ActsAsTaggableOn::Tagging, :count).by(1)
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
if ActsAsTaggableOn::Utils.supports_concurrency?
|
|
584
|
+
xit 'should not duplicate tags added on different threads' do
|
|
585
|
+
#TODO, try with more threads and fix deadlock
|
|
586
|
+
thread_count = 4
|
|
587
|
+
barrier = Barrier.new thread_count
|
|
588
|
+
|
|
589
|
+
expect {
|
|
590
|
+
thread_count.times.map do |idx|
|
|
591
|
+
Thread.start do
|
|
592
|
+
connor = TaggableModel.first_or_create(name: 'Connor')
|
|
593
|
+
connor.tag_list = 'There, can, be, only, one'
|
|
594
|
+
barrier.wait
|
|
595
|
+
begin
|
|
596
|
+
connor.save
|
|
597
|
+
rescue ActsAsTaggableOn::DuplicateTagError
|
|
598
|
+
# second save should succeed
|
|
599
|
+
connor.save
|
|
600
|
+
end
|
|
601
|
+
end
|
|
602
|
+
end.map(&:join)
|
|
603
|
+
}.to change(ActsAsTaggableOn::Tag, :count).by(5)
|
|
604
|
+
end
|
|
605
|
+
end
|
|
492
606
|
end
|
|
493
607
|
|
|
494
|
-
describe
|
|
608
|
+
describe 'Associations' do
|
|
495
609
|
before(:each) do
|
|
496
|
-
@taggable = TaggableModel.create(:
|
|
610
|
+
@taggable = TaggableModel.create(tag_list: 'awesome, epic')
|
|
497
611
|
end
|
|
498
612
|
|
|
499
|
-
it
|
|
613
|
+
it 'should not remove tags when creating associated objects' do
|
|
500
614
|
@taggable.untaggable_models.create!
|
|
501
615
|
@taggable.reload
|
|
502
|
-
@taggable.tag_list.
|
|
616
|
+
expect(@taggable.tag_list.size).to eq(2)
|
|
503
617
|
end
|
|
504
618
|
end
|
|
505
619
|
|
|
506
|
-
describe
|
|
507
|
-
it
|
|
508
|
-
|
|
620
|
+
describe 'grouped_column_names_for method' do
|
|
621
|
+
it 'should return all column names joined for Tag GROUP clause' do
|
|
622
|
+
# NOTE: type column supports an STI Tag subclass in the test suite, though
|
|
623
|
+
# isn't included by default in the migration generator
|
|
624
|
+
expect(@taggable.grouped_column_names_for(ActsAsTaggableOn::Tag))
|
|
625
|
+
.to eq('tags.id, tags.name, tags.taggings_count, tags.type')
|
|
509
626
|
end
|
|
510
627
|
|
|
511
|
-
it
|
|
512
|
-
@taggable.grouped_column_names_for(TaggableModel).
|
|
628
|
+
it 'should return all column names joined for TaggableModel GROUP clause' do
|
|
629
|
+
expect(@taggable.grouped_column_names_for(TaggableModel)).to eq('taggable_models.id, taggable_models.name, taggable_models.type')
|
|
513
630
|
end
|
|
514
631
|
|
|
515
|
-
it
|
|
516
|
-
@taggable.grouped_column_names_for(TaggableModel).
|
|
632
|
+
it 'should return all column names joined for NonStandardIdTaggableModel GROUP clause' do
|
|
633
|
+
expect(@taggable.grouped_column_names_for(TaggableModel)).to eq("taggable_models.#{TaggableModel.primary_key}, taggable_models.name, taggable_models.type")
|
|
517
634
|
end
|
|
518
635
|
end
|
|
519
636
|
|
|
520
|
-
describe
|
|
637
|
+
describe 'NonStandardIdTaggable' do
|
|
521
638
|
before(:each) do
|
|
522
|
-
|
|
523
|
-
@
|
|
524
|
-
@taggables = [@taggable, NonStandardIdTaggableModel.new(:name => "John Doe")]
|
|
639
|
+
@taggable = NonStandardIdTaggableModel.new(name: 'Bob Jones')
|
|
640
|
+
@taggables = [@taggable, NonStandardIdTaggableModel.new(name: 'John Doe')]
|
|
525
641
|
end
|
|
526
642
|
|
|
527
|
-
it
|
|
643
|
+
it 'should have tag types' do
|
|
528
644
|
[:tags, :languages, :skills, :needs, :offerings].each do |type|
|
|
529
|
-
NonStandardIdTaggableModel.tag_types.
|
|
645
|
+
expect(NonStandardIdTaggableModel.tag_types).to include type
|
|
530
646
|
end
|
|
531
647
|
|
|
532
|
-
@taggable.tag_types.
|
|
648
|
+
expect(@taggable.tag_types).to eq(NonStandardIdTaggableModel.tag_types)
|
|
533
649
|
end
|
|
534
650
|
|
|
535
|
-
it
|
|
536
|
-
NonStandardIdTaggableModel.tag_counts_on(:tags).
|
|
651
|
+
it 'should have tag_counts_on' do
|
|
652
|
+
expect(NonStandardIdTaggableModel.tag_counts_on(:tags)).to be_empty
|
|
537
653
|
|
|
538
|
-
@taggable.tag_list =
|
|
654
|
+
@taggable.tag_list = %w(awesome epic)
|
|
539
655
|
@taggable.save
|
|
540
656
|
|
|
541
|
-
NonStandardIdTaggableModel.tag_counts_on(:tags).length.
|
|
542
|
-
@taggable.tag_counts_on(:tags).length.
|
|
657
|
+
expect(NonStandardIdTaggableModel.tag_counts_on(:tags).length).to eq(2)
|
|
658
|
+
expect(@taggable.tag_counts_on(:tags).length).to eq(2)
|
|
543
659
|
end
|
|
544
660
|
|
|
545
|
-
it
|
|
546
|
-
NonStandardIdTaggableModel.tags_on(:tags).
|
|
661
|
+
it 'should have tags_on' do
|
|
662
|
+
expect(NonStandardIdTaggableModel.tags_on(:tags)).to be_empty
|
|
547
663
|
|
|
548
|
-
@taggable.tag_list =
|
|
664
|
+
@taggable.tag_list = %w(awesome epic)
|
|
549
665
|
@taggable.save
|
|
550
666
|
|
|
551
|
-
NonStandardIdTaggableModel.tags_on(:tags).length.
|
|
552
|
-
@taggable.tags_on(:tags).length.
|
|
667
|
+
expect(NonStandardIdTaggableModel.tags_on(:tags).length).to eq(2)
|
|
668
|
+
expect(@taggable.tags_on(:tags).length).to eq(2)
|
|
553
669
|
end
|
|
554
670
|
|
|
555
|
-
it
|
|
556
|
-
@taggable.skill_list =
|
|
557
|
-
@taggable.instance_variable_get(
|
|
671
|
+
it 'should be able to create tags' do
|
|
672
|
+
@taggable.skill_list = 'ruby, rails, css'
|
|
673
|
+
expect(@taggable.instance_variable_get('@skill_list').instance_of?(ActsAsTaggableOn::TagList)).to be_truthy
|
|
558
674
|
|
|
559
|
-
|
|
675
|
+
expect(-> {
|
|
560
676
|
@taggable.save
|
|
561
|
-
}.
|
|
677
|
+
}).to change(ActsAsTaggableOn::Tag, :count).by(3)
|
|
562
678
|
|
|
563
679
|
@taggable.reload
|
|
564
|
-
@taggable.skill_list.sort.
|
|
680
|
+
expect(@taggable.skill_list.sort).to eq(%w(ruby rails css).sort)
|
|
565
681
|
end
|
|
566
682
|
|
|
567
|
-
it
|
|
568
|
-
@taggable.tag_list_on(:test).add(
|
|
569
|
-
@taggable.tag_list_cache_on(:test).
|
|
570
|
-
@taggable.tag_list_on(:test).
|
|
683
|
+
it 'should be able to create tags through the tag list directly' do
|
|
684
|
+
@taggable.tag_list_on(:test).add('hello')
|
|
685
|
+
expect(@taggable.tag_list_cache_on(:test)).to_not be_empty
|
|
686
|
+
expect(@taggable.tag_list_on(:test)).to eq(['hello'])
|
|
571
687
|
|
|
572
688
|
@taggable.save
|
|
573
689
|
@taggable.save_tags
|
|
574
690
|
|
|
575
691
|
@taggable.reload
|
|
576
|
-
@taggable.tag_list_on(:test).
|
|
692
|
+
expect(@taggable.tag_list_on(:test)).to eq(['hello'])
|
|
577
693
|
end
|
|
578
694
|
end
|
|
579
695
|
|
|
580
|
-
describe
|
|
581
|
-
context
|
|
696
|
+
describe 'Dirty Objects' do
|
|
697
|
+
context 'with un-contexted tags' do
|
|
582
698
|
before(:each) do
|
|
583
|
-
@taggable = TaggableModel.create(:
|
|
699
|
+
@taggable = TaggableModel.create(tag_list: 'awesome, epic')
|
|
584
700
|
end
|
|
585
701
|
|
|
586
|
-
context
|
|
702
|
+
context 'when tag_list changed' do
|
|
587
703
|
before(:each) do
|
|
588
|
-
@taggable.changes.
|
|
704
|
+
expect(@taggable.changes).to be_empty
|
|
589
705
|
@taggable.tag_list = 'one'
|
|
590
706
|
end
|
|
591
707
|
|
|
592
708
|
it 'should show changes of dirty object' do
|
|
593
|
-
@taggable.changes.
|
|
709
|
+
expect(@taggable.changes).to eq({'tag_list' => ['awesome, epic', ['one']]})
|
|
594
710
|
end
|
|
595
711
|
|
|
596
712
|
it 'flags tag_list as changed' do
|
|
597
|
-
@taggable.tag_list_changed
|
|
713
|
+
expect(@taggable.tag_list_changed?).to be_truthy
|
|
598
714
|
end
|
|
599
715
|
|
|
600
716
|
it 'preserves original value' do
|
|
601
|
-
@taggable.tag_list_was.
|
|
717
|
+
expect(@taggable.tag_list_was).to eq('awesome, epic')
|
|
602
718
|
end
|
|
603
719
|
|
|
604
720
|
it 'shows what the change was' do
|
|
605
|
-
@taggable.tag_list_change.
|
|
721
|
+
expect(@taggable.tag_list_change).to eq(['awesome, epic', ['one']])
|
|
606
722
|
end
|
|
607
723
|
end
|
|
608
724
|
|
|
609
725
|
context 'when tag_list is the same' do
|
|
610
726
|
before(:each) do
|
|
611
|
-
@taggable.tag_list =
|
|
727
|
+
@taggable.tag_list = 'awesome, epic'
|
|
612
728
|
end
|
|
613
729
|
|
|
614
730
|
it 'is not flagged as changed' do
|
|
615
|
-
@taggable.tag_list_changed
|
|
731
|
+
expect(@taggable.tag_list_changed?).to be_falsy
|
|
616
732
|
end
|
|
617
733
|
|
|
618
734
|
it 'does not show any changes to the taggable item' do
|
|
619
|
-
@taggable.changes.
|
|
735
|
+
expect(@taggable.changes).to be_empty
|
|
620
736
|
end
|
|
621
737
|
|
|
622
738
|
context "and using a delimiter different from a ','" do
|
|
@@ -630,64 +746,135 @@ describe "Taggable" do
|
|
|
630
746
|
end
|
|
631
747
|
|
|
632
748
|
it 'does not show any changes to the taggable item when using array assignments' do
|
|
633
|
-
@taggable.tag_list =
|
|
634
|
-
@taggable.changes.
|
|
749
|
+
@taggable.tag_list = %w(awesome epic)
|
|
750
|
+
expect(@taggable.changes).to be_empty
|
|
635
751
|
end
|
|
636
752
|
end
|
|
637
753
|
end
|
|
638
754
|
end
|
|
639
755
|
|
|
640
|
-
context
|
|
756
|
+
context 'with context tags' do
|
|
641
757
|
before(:each) do
|
|
642
|
-
@taggable = TaggableModel.create(
|
|
758
|
+
@taggable = TaggableModel.create('language_list' => 'awesome, epic')
|
|
643
759
|
end
|
|
644
760
|
|
|
645
|
-
context
|
|
761
|
+
context 'when language_list changed' do
|
|
646
762
|
before(:each) do
|
|
647
|
-
@taggable.changes.
|
|
763
|
+
expect(@taggable.changes).to be_empty
|
|
648
764
|
@taggable.language_list = 'one'
|
|
649
765
|
end
|
|
650
766
|
|
|
651
767
|
it 'should show changes of dirty object' do
|
|
652
|
-
@taggable.changes.
|
|
768
|
+
expect(@taggable.changes).to eq({'language_list' => ['awesome, epic', ['one']]})
|
|
653
769
|
end
|
|
654
770
|
|
|
655
771
|
it 'flags language_list as changed' do
|
|
656
|
-
@taggable.language_list_changed
|
|
772
|
+
expect(@taggable.language_list_changed?).to be_truthy
|
|
657
773
|
end
|
|
658
774
|
|
|
659
775
|
it 'preserves original value' do
|
|
660
|
-
@taggable.language_list_was.
|
|
776
|
+
expect(@taggable.language_list_was).to eq('awesome, epic')
|
|
661
777
|
end
|
|
662
778
|
|
|
663
779
|
it 'shows what the change was' do
|
|
664
|
-
@taggable.language_list_change.
|
|
780
|
+
expect(@taggable.language_list_change).to eq(['awesome, epic', ['one']])
|
|
665
781
|
end
|
|
666
782
|
|
|
667
783
|
it 'shows what the changes were' do
|
|
668
|
-
@taggable.language_list_changes.
|
|
784
|
+
expect(@taggable.language_list_changes).to eq(['awesome, epic', ['one']])
|
|
669
785
|
end
|
|
670
786
|
end
|
|
671
787
|
|
|
672
788
|
context 'when language_list is the same' do
|
|
673
789
|
before(:each) do
|
|
674
|
-
@taggable.language_list =
|
|
790
|
+
@taggable.language_list = 'awesome, epic'
|
|
675
791
|
end
|
|
676
792
|
|
|
677
793
|
it 'is not flagged as changed' do
|
|
678
|
-
@taggable.language_list_changed
|
|
794
|
+
expect(@taggable.language_list_changed?).to be_falsy
|
|
679
795
|
end
|
|
680
796
|
|
|
681
797
|
it 'does not show any changes to the taggable item' do
|
|
682
|
-
@taggable.changes.
|
|
798
|
+
expect(@taggable.changes).to be_empty
|
|
799
|
+
end
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
describe 'Autogenerated methods' do
|
|
805
|
+
it 'should be overridable' do
|
|
806
|
+
expect(TaggableModel.create(tag_list: 'woo').tag_list_submethod_called).to be_truthy
|
|
807
|
+
end
|
|
808
|
+
end
|
|
809
|
+
|
|
810
|
+
# See https://github.com/mbleigh/acts-as-taggable-on/pull/457 for details
|
|
811
|
+
context 'tag_counts and aggreating scopes, compatability with MySQL ' do
|
|
812
|
+
before(:each) do
|
|
813
|
+
TaggableModel.new(:name => 'Barb Jones').tap { |t| t.tag_list = %w(awesome fun) }.save
|
|
814
|
+
TaggableModel.new(:name => 'John Doe').tap { |t| t.tag_list = %w(cool fun hella) }.save
|
|
815
|
+
TaggableModel.new(:name => 'Jo Doe').tap { |t| t.tag_list = %w(curious young naive sharp) }.save
|
|
816
|
+
|
|
817
|
+
TaggableModel.all.each { |t| t.save }
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
context 'Model.limit(x).tag_counts.sum(:tags_count)' do
|
|
821
|
+
it 'should not break on Mysql' do
|
|
822
|
+
# Activerecord 3.2 return a string
|
|
823
|
+
expect(TaggableModel.limit(2).tag_counts.sum('tags_count').to_i).to eq(5)
|
|
824
|
+
end
|
|
825
|
+
end
|
|
826
|
+
|
|
827
|
+
context 'regression prevention, just making sure these esoteric queries still work' do
|
|
828
|
+
context 'Model.tag_counts.limit(x)' do
|
|
829
|
+
it 'should limit the tag objects (not very useful, of course)' do
|
|
830
|
+
array_of_tag_counts = TaggableModel.tag_counts.limit(2)
|
|
831
|
+
expect(array_of_tag_counts.count).to eq(2)
|
|
832
|
+
end
|
|
833
|
+
end
|
|
834
|
+
|
|
835
|
+
context 'Model.tag_counts.sum(:tags_count)' do
|
|
836
|
+
it 'should limit the total tags used' do
|
|
837
|
+
expect(TaggableModel.tag_counts.sum(:tags_count).to_i).to eq(9)
|
|
838
|
+
end
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
context 'Model.tag_counts.limit(2).sum(:tags_count)' do
|
|
842
|
+
it 'limit should have no effect; this is just a sanity check' do
|
|
843
|
+
expect(TaggableModel.tag_counts.limit(2).sum(:tags_count).to_i).to eq(9)
|
|
683
844
|
end
|
|
684
845
|
end
|
|
685
846
|
end
|
|
686
847
|
end
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
if ActsAsTaggableOn::Utils.using_postgresql?
|
|
851
|
+
if ActsAsTaggableOn::Utils.postgresql_support_json?
|
|
852
|
+
describe 'Taggable model with json columns' do
|
|
853
|
+
before(:each) do
|
|
854
|
+
@taggable = TaggableModelWithJson.new(:name => 'Bob Jones')
|
|
855
|
+
@taggables = [@taggable, TaggableModelWithJson.new(:name => 'John Doe')]
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
it 'should be able to find by tag with context' do
|
|
859
|
+
@taggable.skill_list = 'ruby, rails, css'
|
|
860
|
+
@taggable.tag_list = 'bob, charlie'
|
|
861
|
+
@taggable.save
|
|
862
|
+
|
|
863
|
+
expect(TaggableModelWithJson.tagged_with('ruby').first).to eq(@taggable)
|
|
864
|
+
expect(TaggableModelWithJson.tagged_with('ruby, css').first).to eq(@taggable)
|
|
865
|
+
expect(TaggableModelWithJson.tagged_with('bob', :on => :skills).first).to_not eq(@taggable)
|
|
866
|
+
expect(TaggableModelWithJson.tagged_with('bob', :on => :tags).first).to eq(@taggable)
|
|
867
|
+
end
|
|
687
868
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
869
|
+
it 'should be able to find tagged with any tag' do
|
|
870
|
+
bob = TaggableModelWithJson.create(:name => 'Bob', :tag_list => 'fitter, happier, more productive', :skill_list => 'ruby, rails, css')
|
|
871
|
+
frank = TaggableModelWithJson.create(:name => 'Frank', :tag_list => 'weaker, depressed, inefficient', :skill_list => 'ruby, rails, css')
|
|
872
|
+
steve = TaggableModelWithJson.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
|
|
873
|
+
|
|
874
|
+
expect(TaggableModelWithJson.tagged_with(%w(ruby java), :order => 'taggable_model_with_jsons.name', :any => true).to_a).to eq([bob, frank, steve])
|
|
875
|
+
expect(TaggableModelWithJson.tagged_with(%w(c++ fitter), :order => 'taggable_model_with_jsons.name', :any => true).to_a).to eq([bob, steve])
|
|
876
|
+
expect(TaggableModelWithJson.tagged_with(%w(depressed css), :order => 'taggable_model_with_jsons.name', :any => true).to_a).to eq([bob, frank])
|
|
877
|
+
end
|
|
691
878
|
end
|
|
692
879
|
end
|
|
693
880
|
end
|