make_taggable 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
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