acts-as-taggable-on 12.0.0 → 13.0.0

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