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