acts-as-taggable-on 3.5.0 → 4.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +14 -18
- data/Appraisals +9 -8
- data/CHANGELOG.md +3 -1
- data/Gemfile +1 -1
- data/README.md +41 -3
- data/acts-as-taggable-on.gemspec +3 -3
- data/db/migrate/2_add_missing_unique_indices.rb +3 -2
- data/db/migrate/6_add_missing_indexes.rb +12 -0
- data/gemfiles/activerecord_4.0.gemfile +3 -2
- data/gemfiles/activerecord_4.1.gemfile +3 -2
- data/gemfiles/activerecord_4.2.gemfile +2 -3
- data/gemfiles/{activerecord_3.2.gemfile → activerecord_5.0.gemfile} +2 -2
- data/lib/acts-as-taggable-on.rb +16 -12
- data/lib/acts_as_taggable_on/engine.rb +0 -1
- data/lib/acts_as_taggable_on/tag.rb +6 -2
- data/lib/acts_as_taggable_on/tag_list.rb +2 -13
- data/lib/acts_as_taggable_on/taggable/cache.rb +1 -1
- data/lib/acts_as_taggable_on/taggable/collection.rb +6 -3
- data/lib/acts_as_taggable_on/taggable/core.rb +21 -16
- data/lib/acts_as_taggable_on/taggable/ownership.rb +3 -3
- data/lib/acts_as_taggable_on/tagger.rb +12 -11
- data/lib/acts_as_taggable_on/tagging.rb +4 -14
- data/lib/acts_as_taggable_on/utils.rb +2 -3
- data/lib/acts_as_taggable_on/version.rb +1 -1
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +10 -1
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +1 -1
- data/spec/acts_as_taggable_on/caching_spec.rb +22 -0
- data/spec/acts_as_taggable_on/tag_list_spec.rb +27 -1
- data/spec/acts_as_taggable_on/tag_spec.rb +15 -0
- data/spec/acts_as_taggable_on/taggable_spec.rb +19 -5
- data/spec/acts_as_taggable_on/tagging_spec.rb +64 -10
- data/spec/internal/db/schema.rb +7 -3
- data/spec/support/database.rb +1 -7
- metadata +12 -21
- data/lib/acts_as_taggable_on/compatibility.rb +0 -35
- data/lib/acts_as_taggable_on/tag_list_parser.rb +0 -21
- data/spec/acts_as_taggable_on/tag_list_parser_spec.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c10b1bdc1cfdce1f5faa7db0cb813257657bcda
|
4
|
+
data.tar.gz: fdc07fbeaf0a0fe45e1410b2f6a52078a168ff8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1542dd8c7ebafeed4794f6f734da1e98f9641d7ddda18fa93c7e49ec4d5b14867353e065a6f3598050d0606f3e2809c5034a07c9f91385f22c90159dad202c50
|
7
|
+
data.tar.gz: aba26b02cbc655676003bfb6d73092ab49dae44013985a6838b187b3f4920507e684e73fab8a53c7d8b11e036cbc58a608943e3116ebee4ff10bf7df8fea6e80
|
data/.travis.yml
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
language: ruby
|
2
|
+
cache: bundler
|
2
3
|
|
3
4
|
rvm:
|
5
|
+
- 2.3.1
|
6
|
+
- 2.2.5
|
4
7
|
- 2.1
|
5
|
-
- 2.2
|
6
8
|
- 2.0.0
|
7
|
-
- 1.9.3
|
8
|
-
- rbx-2
|
9
9
|
|
10
10
|
env:
|
11
11
|
- DB=sqlite3
|
@@ -13,28 +13,24 @@ env:
|
|
13
13
|
- DB=postgresql
|
14
14
|
|
15
15
|
gemfile:
|
16
|
-
- gemfiles/
|
17
|
-
- gemfiles/activerecord_4.
|
16
|
+
- gemfiles/activerecord_5.0.gemfile
|
17
|
+
- gemfiles/activerecord_4.2.gemfile
|
18
18
|
- gemfiles/activerecord_4.1.gemfile
|
19
|
+
- gemfiles/activerecord_4.0.gemfile
|
19
20
|
|
20
21
|
sudo: false
|
21
22
|
|
22
23
|
bundler_args: '--without local_development --jobs 3 --retry 3'
|
23
24
|
|
25
|
+
before_install:
|
26
|
+
- gem install bundler
|
27
|
+
|
24
28
|
script: bundle exec rake
|
25
29
|
|
26
30
|
matrix:
|
27
|
-
fast_finish: true
|
28
|
-
allow_failures:
|
29
|
-
- gemfile: gemfiles/activerecord_edge.gemfile
|
30
|
-
- rvm: rbx-2
|
31
31
|
exclude:
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
gemfile: gemfiles/activerecord_4.1.gemfile
|
38
|
-
- rvm: rbx-2
|
39
|
-
gemfile: gemfiles/activerecord_3.2.gemfile
|
40
|
-
|
32
|
+
- rvm: 2.0.0
|
33
|
+
gemfile: gemfiles/activerecord_5.0.gemfile
|
34
|
+
- rvm: 2.1
|
35
|
+
gemfile: gemfiles/activerecord_5.0.gemfile
|
36
|
+
fast_finish: true
|
data/Appraisals
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
-
appraise
|
2
|
-
gem
|
1
|
+
appraise 'activerecord-5.0' do
|
2
|
+
gem 'activerecord', "~> 5.0.0"
|
3
3
|
end
|
4
4
|
|
5
|
-
appraise "activerecord-4.
|
6
|
-
gem "activerecord",
|
5
|
+
appraise "activerecord-4.2" do
|
6
|
+
gem "activerecord", "~> 4.2.0"
|
7
7
|
end
|
8
8
|
|
9
9
|
appraise "activerecord-4.1" do
|
10
|
-
gem "activerecord",
|
10
|
+
gem "activerecord", "~> 4.1.0"
|
11
|
+
gem 'mysql2', '~> 0.3.21'
|
11
12
|
end
|
12
13
|
|
13
|
-
appraise "activerecord-4.
|
14
|
-
gem "
|
15
|
-
gem
|
14
|
+
appraise "activerecord-4.0" do
|
15
|
+
gem "activerecord", "~> 4.0.0"
|
16
|
+
gem 'mysql2', '~> 0.3.21'
|
16
17
|
end
|
data/CHANGELOG.md
CHANGED
@@ -4,10 +4,12 @@ Each change should fall into categories that would affect whether the release is
|
|
4
4
|
|
5
5
|
As such, a _Feature_ would map to either major or minor. A _bug fix_ to a patch. And _misc_ is either minor or patch, the difference being kind of fuzzy for the purposes of history. Adding tests would be patch level.
|
6
6
|
|
7
|
-
### [3.5.0 / 2015-
|
7
|
+
### [3.5.0 / 2015-03-03](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.4.4...v3.5.0)
|
8
8
|
|
9
9
|
* Fixes
|
10
10
|
* [@rikettsie Fixed collation for MySql via rake rule or config parameter](https://github.com/mbleigh/acts-as-taggable-on/pull/634)
|
11
|
+
*Misc
|
12
|
+
* [@pcupueran Add rspec test for tagging_spec completeness]()
|
11
13
|
|
12
14
|
### [3.4.4 / 2015-02-11](https://github.com/mbleigh/acts-as-taggable-on/compare/v3.4.3...v3.4.4)
|
13
15
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# ActsAsTaggableOn
|
2
|
+
|
3
|
+
[![Join the chat at https://gitter.im/mbleigh/acts-as-taggable-on](https://badges.gitter.im/mbleigh/acts-as-taggable-on.svg)](https://gitter.im/mbleigh/acts-as-taggable-on?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
2
4
|
[![Gem Version](https://badge.fury.io/rb/acts-as-taggable-on.svg)](http://badge.fury.io/rb/acts-as-taggable-on)
|
3
5
|
[![Build Status](https://secure.travis-ci.org/mbleigh/acts-as-taggable-on.png)](http://travis-ci.org/mbleigh/acts-as-taggable-on)
|
4
6
|
[![Code Climate](https://codeclimate.com/github/mbleigh/acts-as-taggable-on.png)](https://codeclimate.com/github/mbleigh/acts-as-taggable-on)
|
@@ -89,7 +91,7 @@ end
|
|
89
91
|
|
90
92
|
class UsersController < ApplicationController
|
91
93
|
def user_params
|
92
|
-
params.require(:user).permit(:name, :tag_list
|
94
|
+
params.require(:user).permit(:name, :tag_list) ## Rails 4 strong params usage
|
93
95
|
end
|
94
96
|
end
|
95
97
|
|
@@ -273,7 +275,7 @@ User.tagged_with("same", :on => :customs) # => [@user]
|
|
273
275
|
|
274
276
|
### Tag Parsers
|
275
277
|
|
276
|
-
If you want to change how tags are parsed, you can define
|
278
|
+
If you want to change how tags are parsed, you can define your own implementation:
|
277
279
|
|
278
280
|
```ruby
|
279
281
|
class MyParser < ActsAsTaggableOn::GenericParser
|
@@ -302,7 +304,7 @@ Now you can use this parser, passing it as parameter:
|
|
302
304
|
Or change it globally:
|
303
305
|
|
304
306
|
```ruby
|
305
|
-
|
307
|
+
ActsAsTaggableOn.default_parser = MyParser
|
306
308
|
@user = User.new(:name => "Bobby")
|
307
309
|
@user.tag_list = "east|south"
|
308
310
|
@user.tag_list # => ["east", "south"]
|
@@ -331,6 +333,42 @@ Photo.tagged_with("paris", :on => :locations, :owned_by => @some_user)
|
|
331
333
|
@some_user.tag(@some_photo, :with => "paris, normandy", :on => :locations, :skip_save => true) #won't save @some_photo object
|
332
334
|
```
|
333
335
|
|
336
|
+
#### Working with Owned Tags
|
337
|
+
Note that `tag_list` only returns tags whose taggings do not have an owner. Continuing from the above example:
|
338
|
+
```ruby
|
339
|
+
@some_photo.tag_list # => []
|
340
|
+
```
|
341
|
+
To retrieve all tags of an object (regardless of ownership) or if only one owner can tag the object, use `all_tags_list`.
|
342
|
+
|
343
|
+
##### Adding owned tags
|
344
|
+
Note that **owned tags** are added all at once, in the form of ***comma seperated tags*** in string.
|
345
|
+
Also, when you try to add **owned tags** again, it simply overwrites the previous set of **owned tags**.
|
346
|
+
So to append tags in previously existing **owned tags** list, go as follows:
|
347
|
+
```ruby
|
348
|
+
def add_owned_tag
|
349
|
+
@some_item = Item.find(params[:id])
|
350
|
+
owned_tag_list = @some_item.all_tag_list - @some_item.tag_list
|
351
|
+
owned_tag_list += [(params[:tag])]
|
352
|
+
@tag_owner.tag(@some_item, :with => stringify(owned_tag_list), :on => :tags)
|
353
|
+
@some_item.save
|
354
|
+
end
|
355
|
+
|
356
|
+
def stringify(tag_list)
|
357
|
+
tag_list.inject('') { |memo, tag| memo += (tag + ',') }[0..-1]
|
358
|
+
end
|
359
|
+
```
|
360
|
+
##### Removing owned tags
|
361
|
+
Similarly as above, removing will be as follows:
|
362
|
+
```ruby
|
363
|
+
def remove_owned_tag
|
364
|
+
@some_item = Item.find(params[:id])
|
365
|
+
owned_tag_list = @some_item.all_tag_list - @some_item.tag_list
|
366
|
+
owned_tag_list -= [(params[:tag])]
|
367
|
+
@tag_owner.tag(@some_item, :with => stringify(owned_tag_list), :on => :tags)
|
368
|
+
@some_item.save
|
369
|
+
end
|
370
|
+
```
|
371
|
+
|
334
372
|
### Dirty objects
|
335
373
|
|
336
374
|
```ruby
|
data/acts-as-taggable-on.gemspec
CHANGED
@@ -16,16 +16,16 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.files = `git ls-files`.split($/)
|
17
17
|
gem.test_files = gem.files.grep(%r{^spec/})
|
18
18
|
gem.require_paths = ['lib']
|
19
|
-
gem.required_ruby_version = '>=
|
19
|
+
gem.required_ruby_version = '>= 2.0.0'
|
20
20
|
|
21
21
|
if File.exist?('UPGRADING.md')
|
22
22
|
gem.post_install_message = File.read('UPGRADING.md')
|
23
23
|
end
|
24
24
|
|
25
|
-
gem.add_runtime_dependency 'activerecord',
|
25
|
+
gem.add_runtime_dependency 'activerecord', ['>= 4.0']
|
26
26
|
|
27
27
|
gem.add_development_dependency 'sqlite3'
|
28
|
-
gem.add_development_dependency 'mysql2', '~> 0.3
|
28
|
+
gem.add_development_dependency 'mysql2', '~> 0.3'
|
29
29
|
gem.add_development_dependency 'pg'
|
30
30
|
|
31
31
|
gem.add_development_dependency 'rspec-rails'
|
@@ -2,7 +2,7 @@ class AddMissingUniqueIndices < ActiveRecord::Migration
|
|
2
2
|
def self.up
|
3
3
|
add_index :tags, :name, unique: true
|
4
4
|
|
5
|
-
remove_index :taggings, :tag_id
|
5
|
+
remove_index :taggings, :tag_id if index_exists?(:taggings, :tag_id)
|
6
6
|
remove_index :taggings, [:taggable_id, :taggable_type, :context]
|
7
7
|
add_index :taggings,
|
8
8
|
[:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type],
|
@@ -13,7 +13,8 @@ class AddMissingUniqueIndices < ActiveRecord::Migration
|
|
13
13
|
remove_index :tags, :name
|
14
14
|
|
15
15
|
remove_index :taggings, name: 'taggings_idx'
|
16
|
-
|
16
|
+
|
17
|
+
add_index :taggings, :tag_id unless index_exists?(:taggings, :tag_id)
|
17
18
|
add_index :taggings, [:taggable_id, :taggable_type, :context]
|
18
19
|
end
|
19
20
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class AddMissingIndexes < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
add_index :taggings, :tag_id
|
4
|
+
add_index :taggings, :taggable_id
|
5
|
+
add_index :taggings, :taggable_type
|
6
|
+
add_index :taggings, :tagger_id
|
7
|
+
add_index :taggings, :context
|
8
|
+
|
9
|
+
add_index :taggings, [:tagger_id, :tagger_type]
|
10
|
+
add_index :taggings, [:taggable_id, :taggable_type, :tagger_id, :context], name: 'taggings_idy'
|
11
|
+
end
|
12
|
+
end
|
@@ -2,14 +2,15 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "activerecord",
|
5
|
+
gem "activerecord", "~> 4.0.0"
|
6
|
+
gem "mysql2", "~> 0.3.21"
|
6
7
|
|
7
8
|
group :local_development do
|
8
9
|
gem "guard"
|
9
10
|
gem "guard-rspec"
|
10
11
|
gem "appraisal"
|
11
12
|
gem "rake"
|
12
|
-
gem "byebug", :
|
13
|
+
gem "byebug", :platforms => [:mri_21, :mri_22, :mri_23]
|
13
14
|
end
|
14
15
|
|
15
16
|
gemspec :path => "../"
|
@@ -2,14 +2,15 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "activerecord",
|
5
|
+
gem "activerecord", "~> 4.1.0"
|
6
|
+
gem "mysql2", "~> 0.3.21"
|
6
7
|
|
7
8
|
group :local_development do
|
8
9
|
gem "guard"
|
9
10
|
gem "guard-rspec"
|
10
11
|
gem "appraisal"
|
11
12
|
gem "rake"
|
12
|
-
gem "byebug", :
|
13
|
+
gem "byebug", :platforms => [:mri_21, :mri_22, :mri_23]
|
13
14
|
end
|
14
15
|
|
15
16
|
gemspec :path => "../"
|
@@ -2,15 +2,14 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "
|
6
|
-
gem "activerecord", :github => "rails/rails", :branch => "4-2-stable"
|
5
|
+
gem "activerecord", "~> 4.2.0"
|
7
6
|
|
8
7
|
group :local_development do
|
9
8
|
gem "guard"
|
10
9
|
gem "guard-rspec"
|
11
10
|
gem "appraisal"
|
12
11
|
gem "rake"
|
13
|
-
gem "byebug", :
|
12
|
+
gem "byebug", :platforms => [:mri_21, :mri_22, :mri_23]
|
14
13
|
end
|
15
14
|
|
16
15
|
gemspec :path => "../"
|
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "activerecord",
|
5
|
+
gem "activerecord", "~> 5.0.0"
|
6
6
|
|
7
7
|
group :local_development do
|
8
8
|
gem "guard"
|
9
9
|
gem "guard-rspec"
|
10
10
|
gem "appraisal"
|
11
11
|
gem "rake"
|
12
|
-
gem "byebug", :
|
12
|
+
gem "byebug", :platforms => [:mri_21, :mri_22, :mri_23]
|
13
13
|
end
|
14
14
|
|
15
15
|
gemspec :path => "../"
|
data/lib/acts-as-taggable-on.rb
CHANGED
@@ -2,7 +2,12 @@ require 'active_record'
|
|
2
2
|
require 'active_record/version'
|
3
3
|
require 'active_support/core_ext/module'
|
4
4
|
|
5
|
-
|
5
|
+
begin
|
6
|
+
require 'rails/engine'
|
7
|
+
require 'acts_as_taggable_on/engine'
|
8
|
+
rescue LoadError
|
9
|
+
|
10
|
+
end
|
6
11
|
|
7
12
|
require 'digest/sha1'
|
8
13
|
|
@@ -13,7 +18,6 @@ module ActsAsTaggableOn
|
|
13
18
|
autoload :TagList
|
14
19
|
autoload :GenericParser
|
15
20
|
autoload :DefaultParser
|
16
|
-
autoload :TagListParser
|
17
21
|
autoload :Taggable
|
18
22
|
autoload :Tagger
|
19
23
|
autoload :Tagging
|
@@ -57,9 +61,10 @@ module ActsAsTaggableOn
|
|
57
61
|
end
|
58
62
|
|
59
63
|
class Configuration
|
60
|
-
attr_accessor :
|
61
|
-
:
|
64
|
+
attr_accessor :force_lowercase, :force_parameterize,
|
65
|
+
:remove_unused_tags, :default_parser,
|
62
66
|
:tags_counter
|
67
|
+
attr_reader :delimiter, :strict_case_match
|
63
68
|
|
64
69
|
def initialize
|
65
70
|
@delimiter = ','
|
@@ -73,9 +78,7 @@ module ActsAsTaggableOn
|
|
73
78
|
end
|
74
79
|
|
75
80
|
def strict_case_match=(force_cs)
|
76
|
-
|
77
|
-
@strict_case_match = force_cs
|
78
|
-
end
|
81
|
+
@strict_case_match = force_cs unless @force_binary_collation
|
79
82
|
end
|
80
83
|
|
81
84
|
def delimiter=(string)
|
@@ -89,7 +92,7 @@ WARNING
|
|
89
92
|
|
90
93
|
def force_binary_collation=(force_bin)
|
91
94
|
if Utils.using_mysql?
|
92
|
-
if force_bin
|
95
|
+
if force_bin
|
93
96
|
Configuration.apply_binary_collation(true)
|
94
97
|
@force_binary_collation = true
|
95
98
|
@strict_case_match = true
|
@@ -103,10 +106,12 @@ WARNING
|
|
103
106
|
def self.apply_binary_collation(bincoll)
|
104
107
|
if Utils.using_mysql?
|
105
108
|
coll = 'utf8_general_ci'
|
106
|
-
if bincoll
|
107
|
-
|
109
|
+
coll = 'utf8_bin' if bincoll
|
110
|
+
begin
|
111
|
+
ActiveRecord::Migration.execute("ALTER TABLE #{Tag.table_name} MODIFY name varchar(255) CHARACTER SET utf8 COLLATE #{coll};")
|
112
|
+
rescue Exception => e
|
113
|
+
puts "Trapping #{e.class}: collation parameter ignored while migrating for the first time."
|
108
114
|
end
|
109
|
-
ActiveRecord::Migration.execute("ALTER TABLE tags MODIFY name varchar(255) CHARACTER SET utf8 COLLATE #{coll};")
|
110
115
|
end
|
111
116
|
end
|
112
117
|
|
@@ -116,7 +121,6 @@ WARNING
|
|
116
121
|
end
|
117
122
|
|
118
123
|
ActiveSupport.on_load(:active_record) do
|
119
|
-
extend ActsAsTaggableOn::Compatibility
|
120
124
|
extend ActsAsTaggableOn::Taggable
|
121
125
|
include ActsAsTaggableOn::Tagger
|
122
126
|
end
|
@@ -2,8 +2,6 @@
|
|
2
2
|
module ActsAsTaggableOn
|
3
3
|
class Tag < ::ActiveRecord::Base
|
4
4
|
|
5
|
-
attr_accessible :name if defined?(ActiveModel::MassAssignmentSecurity)
|
6
|
-
|
7
5
|
### ASSOCIATIONS:
|
8
6
|
|
9
7
|
has_many :taggings, dependent: :destroy, class_name: '::ActsAsTaggableOn::Tagging'
|
@@ -50,6 +48,12 @@ module ActsAsTaggableOn
|
|
50
48
|
where(clause)
|
51
49
|
end
|
52
50
|
|
51
|
+
def self.for_context(context)
|
52
|
+
joins(:taggings).
|
53
|
+
where(["taggings.context = ?", context]).
|
54
|
+
select("DISTINCT tags.*")
|
55
|
+
end
|
56
|
+
|
53
57
|
### CLASS METHODS:
|
54
58
|
|
55
59
|
def self.find_or_create_with_like_by_name(name)
|
@@ -84,7 +84,8 @@ module ActsAsTaggableOn
|
|
84
84
|
map! { |tag| tag.mb_chars.downcase.to_s } if ActsAsTaggableOn.force_lowercase
|
85
85
|
map!(&:parameterize) if ActsAsTaggableOn.force_parameterize
|
86
86
|
|
87
|
-
uniq!
|
87
|
+
ActsAsTaggableOn.strict_case_match ? uniq! : uniq!{ |tag| tag.downcase }
|
88
|
+
self
|
88
89
|
end
|
89
90
|
|
90
91
|
|
@@ -99,18 +100,6 @@ module ActsAsTaggableOn
|
|
99
100
|
args.flatten!
|
100
101
|
end
|
101
102
|
|
102
|
-
|
103
|
-
## DEPRECATED
|
104
|
-
def self.from(string)
|
105
|
-
ActiveRecord::Base.logger.warn <<WARNING
|
106
|
-
ActsAsTaggableOn::TagList.from is deprecated \
|
107
|
-
and will be removed from v4.0+, use \
|
108
|
-
ActsAsTaggableOn::DefaultParser.new instead
|
109
|
-
WARNING
|
110
|
-
@parser.new(string).parse
|
111
|
-
end
|
112
|
-
|
113
|
-
|
114
103
|
end
|
115
104
|
end
|
116
105
|
|
@@ -73,7 +73,7 @@ module ActsAsTaggableOn::Taggable
|
|
73
73
|
tag_types.map(&:to_s).each do |tag_type|
|
74
74
|
if self.class.send("caching_#{tag_type.singularize}_list?")
|
75
75
|
if tag_list_cache_set_on(tag_type)
|
76
|
-
list = tag_list_cache_on(tag_type).to_a.flatten.compact.join(
|
76
|
+
list = tag_list_cache_on(tag_type).to_a.flatten.compact.join("#{ActsAsTaggableOn.delimiter} ")
|
77
77
|
self["cached_#{tag_type.singularize}_list"] = list
|
78
78
|
end
|
79
79
|
end
|
@@ -138,7 +138,7 @@ module ActsAsTaggableOn::Taggable
|
|
138
138
|
scoped_ids = pluck(table_name_pkey)
|
139
139
|
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN (?)", scoped_ids)
|
140
140
|
else
|
141
|
-
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{safe_to_sql(select(table_name_pkey))})")
|
141
|
+
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{safe_to_sql(except(:select).select(table_name_pkey))})")
|
142
142
|
end
|
143
143
|
|
144
144
|
tagging_scope
|
@@ -169,9 +169,12 @@ module ActsAsTaggableOn::Taggable
|
|
169
169
|
end
|
170
170
|
|
171
171
|
module CalculationMethods
|
172
|
-
|
172
|
+
# Rails 5 TODO: Remove options argument as soon we remove support to
|
173
|
+
# activerecord-deprecated_finders.
|
174
|
+
# See https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation/calculations.rb#L38
|
175
|
+
def count(column_name = :all, options = {})
|
173
176
|
# https://github.com/rails/rails/commit/da9b5d4a8435b744fcf278fffd6d7f1e36d4a4f2
|
174
|
-
super
|
177
|
+
ActsAsTaggableOn::Utils.active_record5? ? super(column_name) : super(column_name, options)
|
175
178
|
end
|
176
179
|
end
|
177
180
|
end
|
@@ -23,18 +23,15 @@ module ActsAsTaggableOn::Taggable
|
|
23
23
|
class_eval do
|
24
24
|
# when preserving tag order, include order option so that for a 'tags' context
|
25
25
|
# the associations tag_taggings & tags are always returned in created order
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
class_name: 'ActsAsTaggableOn::Tag',
|
36
|
-
order: taggings_order
|
37
|
-
|
26
|
+
has_many context_taggings, -> { includes(:tag).order(taggings_order).where(context: tags_type) },
|
27
|
+
as: :taggable,
|
28
|
+
class_name: ActsAsTaggableOn::Tagging,
|
29
|
+
dependent: :destroy
|
30
|
+
|
31
|
+
has_many context_tags, -> { order(taggings_order) },
|
32
|
+
class_name: ActsAsTaggableOn::Tag,
|
33
|
+
through: context_taggings,
|
34
|
+
source: :tag
|
38
35
|
end
|
39
36
|
|
40
37
|
taggable_mixin.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
@@ -246,6 +243,14 @@ module ActsAsTaggableOn::Taggable
|
|
246
243
|
def taggable_mixin
|
247
244
|
@taggable_mixin ||= Module.new
|
248
245
|
end
|
246
|
+
|
247
|
+
private
|
248
|
+
|
249
|
+
# Rails 5 has merged sanitize and quote_value
|
250
|
+
# See https://github.com/rails/rails/blob/master/activerecord/lib/active_record/sanitization.rb#L10
|
251
|
+
def quote_value(value, column = nil)
|
252
|
+
ActsAsTaggableOn::Utils.active_record5? ? super(value) : super(value, column)
|
253
|
+
end
|
249
254
|
end
|
250
255
|
|
251
256
|
# all column names are necessary for PostgreSQL group clause
|
@@ -254,7 +259,7 @@ module ActsAsTaggableOn::Taggable
|
|
254
259
|
end
|
255
260
|
|
256
261
|
def custom_contexts
|
257
|
-
@custom_contexts ||=
|
262
|
+
@custom_contexts ||= taggings.map(&:context).uniq
|
258
263
|
end
|
259
264
|
|
260
265
|
def is_taggable?
|
@@ -333,7 +338,7 @@ module ActsAsTaggableOn::Taggable
|
|
333
338
|
end
|
334
339
|
|
335
340
|
def tagging_contexts
|
336
|
-
|
341
|
+
self.class.tag_types.map(&:to_s) + custom_contexts
|
337
342
|
end
|
338
343
|
|
339
344
|
def process_dirty_object(context, new_list)
|
@@ -407,7 +412,7 @@ module ActsAsTaggableOn::Taggable
|
|
407
412
|
|
408
413
|
# Destroy old taggings:
|
409
414
|
if old_tags.present?
|
410
|
-
taggings.not_owned.by_context(context).
|
415
|
+
taggings.not_owned.by_context(context).where(tag_id: old_tags).destroy_all
|
411
416
|
end
|
412
417
|
|
413
418
|
# Create new taggings:
|
@@ -432,7 +437,7 @@ module ActsAsTaggableOn::Taggable
|
|
432
437
|
tag_lists = tag_types.map {|tags_type| "#{tags_type.to_s.singularize}_list"}
|
433
438
|
super.delete_if {|attr| tag_lists.include? attr }
|
434
439
|
end
|
435
|
-
|
440
|
+
|
436
441
|
##
|
437
442
|
# Override this hook if you wish to subclass {ActsAsTaggableOn::Tag} --
|
438
443
|
# context is provided so that you may conditionally use a Tag subclass
|
@@ -108,9 +108,9 @@ module ActsAsTaggableOn::Taggable
|
|
108
108
|
|
109
109
|
# Find all taggings that belong to the taggable (self), are owned by the owner,
|
110
110
|
# have the correct context, and are removed from the list.
|
111
|
-
ActsAsTaggableOn::Tagging.
|
112
|
-
|
113
|
-
|
111
|
+
ActsAsTaggableOn::Tagging.where(taggable_id: id, taggable_type: self.class.base_class.to_s,
|
112
|
+
tagger_type: owner.class.base_class.to_s, tagger_id: owner.id,
|
113
|
+
tag_id: old_tags, context: context).destroy_all if old_tags.present?
|
114
114
|
|
115
115
|
# Create new taggings:
|
116
116
|
new_tags.each do |tag|
|
@@ -15,18 +15,19 @@ module ActsAsTaggableOn
|
|
15
15
|
# end
|
16
16
|
def acts_as_tagger(opts={})
|
17
17
|
class_eval do
|
18
|
-
|
19
|
-
opts.merge(
|
20
|
-
as: :tagger,
|
21
|
-
dependent: :destroy,
|
22
|
-
class_name: '::ActsAsTaggableOn::Tagging'
|
23
|
-
)
|
18
|
+
owned_taggings_scope = opts.delete(:scope)
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
20
|
+
has_many :owned_taggings, owned_taggings_scope,
|
21
|
+
opts.merge(
|
22
|
+
as: :tagger,
|
23
|
+
class_name: ::ActsAsTaggableOn::Tagging,
|
24
|
+
dependent: :destroy
|
25
|
+
)
|
26
|
+
|
27
|
+
has_many :owned_tags, -> { distinct },
|
28
|
+
class_name: ::ActsAsTaggableOn::Tag,
|
29
|
+
source: :tag,
|
30
|
+
through: :owned_taggings
|
30
31
|
end
|
31
32
|
|
32
33
|
include ActsAsTaggableOn::Tagger::InstanceMethods
|
@@ -1,25 +1,15 @@
|
|
1
1
|
module ActsAsTaggableOn
|
2
2
|
class Tagging < ::ActiveRecord::Base #:nodoc:
|
3
|
-
#TODO, remove from 4.0.0
|
4
|
-
attr_accessible :tag,
|
5
|
-
:tag_id,
|
6
|
-
:context,
|
7
|
-
:taggable,
|
8
|
-
:taggable_type,
|
9
|
-
:taggable_id,
|
10
|
-
:tagger,
|
11
|
-
:tagger_type,
|
12
|
-
:tagger_id if defined?(ActiveModel::MassAssignmentSecurity)
|
13
|
-
|
14
3
|
belongs_to :tag, class_name: '::ActsAsTaggableOn::Tag', counter_cache: ActsAsTaggableOn.tags_counter
|
15
4
|
belongs_to :taggable, polymorphic: true
|
16
|
-
|
5
|
+
|
6
|
+
belongs_to :tagger, {polymorphic: true}.tap {|o| o.merge!(optional: true) if ActsAsTaggableOn::Utils.active_record5? }
|
17
7
|
|
18
8
|
scope :owned_by, ->(owner) { where(tagger: owner) }
|
19
9
|
scope :not_owned, -> { where(tagger_id: nil, tagger_type: nil) }
|
20
10
|
|
21
|
-
scope :by_contexts, ->(contexts
|
22
|
-
scope :by_context, ->(context= 'tags') { by_contexts(context.to_s) }
|
11
|
+
scope :by_contexts, ->(contexts) { where(context: (contexts || 'tags')) }
|
12
|
+
scope :by_context, ->(context = 'tags') { by_contexts(context.to_s) }
|
23
13
|
|
24
14
|
validates_presence_of :context
|
25
15
|
validates_presence_of :tag_id
|
@@ -13,7 +13,6 @@ module ActsAsTaggableOn
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def using_mysql?
|
16
|
-
#We should probably use regex for mysql to support prehistoric adapters
|
17
16
|
connection && connection.adapter_name == 'Mysql2'
|
18
17
|
end
|
19
18
|
|
@@ -21,8 +20,8 @@ module ActsAsTaggableOn
|
|
21
20
|
Digest::SHA1.hexdigest(string)[0..6]
|
22
21
|
end
|
23
22
|
|
24
|
-
def
|
25
|
-
::ActiveRecord::VERSION::MAJOR ==
|
23
|
+
def active_record5?
|
24
|
+
::ActiveRecord::VERSION::MAJOR == 5
|
26
25
|
end
|
27
26
|
|
28
27
|
def like_operator
|
@@ -154,7 +154,7 @@ describe 'Acts As Taggable On' do
|
|
154
154
|
describe 'Tagging Contexts' do
|
155
155
|
it 'should eliminate duplicate tagging contexts ' do
|
156
156
|
TaggableModel.acts_as_taggable_on(:skills, :skills)
|
157
|
-
expect(TaggableModel.tag_types.freq[:skills]).
|
157
|
+
expect(TaggableModel.tag_types.freq[:skills]).to eq(1)
|
158
158
|
end
|
159
159
|
|
160
160
|
it 'should not contain embedded/nested arrays' do
|
@@ -178,6 +178,15 @@ describe 'Acts As Taggable On' do
|
|
178
178
|
TaggableModel.acts_as_taggable_on([nil])
|
179
179
|
}).to_not raise_error
|
180
180
|
end
|
181
|
+
|
182
|
+
it 'should include dynamic contexts in tagging_contexts' do
|
183
|
+
taggable = TaggableModel.create!(name: 'Dynamic Taggable')
|
184
|
+
taggable.set_tag_list_on :colors, 'tag1, tag2, tag3'
|
185
|
+
expect(taggable.tagging_contexts).to eq(%w(tags languages skills needs offerings array colors))
|
186
|
+
taggable.save
|
187
|
+
taggable = TaggableModel.where(name: 'Dynamic Taggable').first
|
188
|
+
expect(taggable.tagging_contexts).to eq(%w(tags languages skills needs offerings array colors))
|
189
|
+
end
|
181
190
|
end
|
182
191
|
|
183
192
|
context 'when tagging context ends in an "s" when singular (ex. "status", "glass", etc.)' do
|
@@ -72,7 +72,7 @@ describe 'acts_as_tagger' do
|
|
72
72
|
expect(@taggable.tag_list_on(:foo_boo)).to be_empty
|
73
73
|
expect(-> {
|
74
74
|
@tagger.tag(@taggable, with: 'this, and, that', on: :foo_boo, force: false)
|
75
|
-
}).to raise_error
|
75
|
+
}).to raise_error(RuntimeError)
|
76
76
|
end
|
77
77
|
|
78
78
|
it 'should not create the tag context on-the-fly when the default is over-ridden' do
|
@@ -77,6 +77,28 @@ describe 'Acts As Taggable On' do
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
+
describe 'with a custom delimiter' do
|
81
|
+
before(:each) do
|
82
|
+
@taggable = CachedModel.new(name: 'Bob Jones')
|
83
|
+
@another_taggable = OtherCachedModel.new(name: 'John Smith')
|
84
|
+
ActsAsTaggableOn.delimiter = ';'
|
85
|
+
end
|
86
|
+
|
87
|
+
after(:all) do
|
88
|
+
ActsAsTaggableOn.delimiter = ','
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should cache tags with custom delimiter' do
|
92
|
+
@taggable.update_attributes(tag_list: 'awesome; epic')
|
93
|
+
expect(@taggable.tag_list).to eq(['awesome', 'epic'])
|
94
|
+
expect(@taggable.cached_tag_list).to eq('awesome; epic')
|
95
|
+
|
96
|
+
@taggable = CachedModel.find_by_name('Bob Jones')
|
97
|
+
expect(@taggable.tag_list).to eq(['awesome', 'epic'])
|
98
|
+
expect(@taggable.cached_tag_list).to eq('awesome; epic')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
80
102
|
describe 'CachingWithArray' do
|
81
103
|
pending '#TODO'
|
82
104
|
end
|
@@ -83,6 +83,18 @@ describe ActsAsTaggableOn::TagList do
|
|
83
83
|
new_tag_list = tag_list.concat(another_tag_list)
|
84
84
|
expect(new_tag_list.class).to eq(ActsAsTaggableOn::TagList)
|
85
85
|
end
|
86
|
+
|
87
|
+
context 'without duplicates' do
|
88
|
+
let(:arr) { ['crazy', 'alien'] }
|
89
|
+
let(:another_tag_list) { ActsAsTaggableOn::TagList.new(*arr) }
|
90
|
+
it 'adds other list' do
|
91
|
+
expect(tag_list.concat(another_tag_list)).to eq(%w[awesome radical crazy alien])
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'adds other array' do
|
95
|
+
expect(tag_list.concat(arr)).to eq(%w[awesome radical crazy alien])
|
96
|
+
end
|
97
|
+
end
|
86
98
|
end
|
87
99
|
|
88
100
|
describe '#to_s' do
|
@@ -92,7 +104,7 @@ describe ActsAsTaggableOn::TagList do
|
|
92
104
|
|
93
105
|
it 'should be able to call to_s on a frozen tag list' do
|
94
106
|
tag_list.freeze
|
95
|
-
expect(-> { tag_list.add('cool', 'rad,bodacious') }).to raise_error
|
107
|
+
expect(-> { tag_list.add('cool', 'rad,bodacious') }).to raise_error(RuntimeError)
|
96
108
|
expect(-> { tag_list.to_s }).to_not raise_error
|
97
109
|
end
|
98
110
|
end
|
@@ -114,6 +126,20 @@ describe ActsAsTaggableOn::TagList do
|
|
114
126
|
|
115
127
|
ActsAsTaggableOn.force_lowercase = false
|
116
128
|
end
|
129
|
+
|
130
|
+
it 'should ignore case when removing duplicates if strict_case_match is false' do
|
131
|
+
tag_list = ActsAsTaggableOn::TagList.new('Junglist', 'JUNGLIST', 'Junglist', 'Massive', 'MASSIVE', 'MASSIVE')
|
132
|
+
|
133
|
+
expect(tag_list.to_s).to eq('Junglist, Massive')
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should not ignore case when removing duplicates if strict_case_match is true' do
|
137
|
+
ActsAsTaggableOn.strict_case_match = true
|
138
|
+
tag_list = ActsAsTaggableOn::TagList.new('Junglist', 'JUNGLIST', 'Junglist', 'Massive', 'MASSIVE', 'MASSIVE')
|
139
|
+
|
140
|
+
expect(tag_list.to_s).to eq('Junglist, JUNGLIST, Massive, MASSIVE')
|
141
|
+
ActsAsTaggableOn.strict_case_match = false
|
142
|
+
end
|
117
143
|
end
|
118
144
|
|
119
145
|
describe 'custom parser' do
|
@@ -55,6 +55,21 @@ describe ActsAsTaggableOn::Tag do
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
describe 'for context' do
|
59
|
+
before(:each) do
|
60
|
+
@user.skill_list.add('ruby')
|
61
|
+
@user.save
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should return tags that have been used in the given context' do
|
65
|
+
expect(ActsAsTaggableOn::Tag.for_context('skills').pluck(:name)).to include('ruby')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should not return tags that have been used in other contexts' do
|
69
|
+
expect(ActsAsTaggableOn::Tag.for_context('needs').pluck(:name)).to_not include('ruby')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
58
73
|
describe 'find or create by name' do
|
59
74
|
before(:each) do
|
60
75
|
@tag.name = 'awesome'
|
@@ -119,6 +119,21 @@ describe 'Taggable' do
|
|
119
119
|
expect(@taggable.tag_counts_on(:tags).length).to eq(2)
|
120
120
|
end
|
121
121
|
|
122
|
+
context 'tag_counts on a collection' do
|
123
|
+
context 'a select clause is specified on the collection' do
|
124
|
+
it 'should return tag counts without raising an error' do
|
125
|
+
expect(TaggableModel.tag_counts_on(:tags)).to be_empty
|
126
|
+
|
127
|
+
@taggable.tag_list = %w(awesome epic)
|
128
|
+
@taggable.save
|
129
|
+
|
130
|
+
expect {
|
131
|
+
expect(TaggableModel.select(:name).tag_counts_on(:tags).length).to eq(2)
|
132
|
+
}.not_to raise_error
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
122
137
|
it 'should have tags_on' do
|
123
138
|
expect(TaggableModel.tags_on(:tags)).to be_empty
|
124
139
|
|
@@ -226,8 +241,10 @@ describe 'Taggable' do
|
|
226
241
|
it "should be able to find a tag using dates" do
|
227
242
|
@taggable.skill_list = "ruby"
|
228
243
|
@taggable.save
|
244
|
+
today = Date.today.to_time.utc
|
245
|
+
tomorrow = Date.tomorrow.to_time.utc
|
229
246
|
|
230
|
-
expect(TaggableModel.tagged_with("ruby", :start_at =>
|
247
|
+
expect(TaggableModel.tagged_with("ruby", :start_at => today, :end_at => tomorrow).count).to eq(1)
|
231
248
|
end
|
232
249
|
|
233
250
|
it "shouldn't be able to find a tag outside date range" do
|
@@ -380,7 +397,6 @@ describe 'Taggable' do
|
|
380
397
|
# Test specific join syntaxes:
|
381
398
|
frank.untaggable_models.create!
|
382
399
|
expect(TaggableModel.tagged_with('rails').joins(:untaggable_models).all_tag_counts.size).to eq(2)
|
383
|
-
expect(TaggableModel.tagged_with('rails').joins(untaggable_models: :taggable_model).all_tag_counts.size).to eq(2)
|
384
400
|
expect(TaggableModel.tagged_with('rails').joins([:untaggable_models]).all_tag_counts.size).to eq(2)
|
385
401
|
end
|
386
402
|
|
@@ -395,7 +411,6 @@ describe 'Taggable' do
|
|
395
411
|
# Test specific join syntaxes:
|
396
412
|
frank.untaggable_models.create!
|
397
413
|
expect(TaggableModel.tagged_with('rails').joins(:untaggable_models).all_tags.size).to eq(2)
|
398
|
-
expect(TaggableModel.tagged_with('rails').joins(untaggable_models: :taggable_model).all_tags.size).to eq(2)
|
399
414
|
expect(TaggableModel.tagged_with('rails').joins([:untaggable_models]).all_tags.size).to eq(2)
|
400
415
|
end
|
401
416
|
|
@@ -459,7 +474,7 @@ describe 'Taggable' do
|
|
459
474
|
|
460
475
|
expect(TaggableModel.tagged_with(%w(bob tricia), wild: true, any: true).to_a.sort_by { |o| o.id }).to eq([bob, frank, steve])
|
461
476
|
expect(TaggableModel.tagged_with(%w(bob tricia), wild: true, exclude: true).to_a).to eq([jim])
|
462
|
-
expect(TaggableModel.tagged_with('ji', wild: true, any: true).to_a
|
477
|
+
expect(TaggableModel.tagged_with('ji', wild: true, any: true).to_a =~ [frank, jim])
|
463
478
|
end
|
464
479
|
end
|
465
480
|
|
@@ -743,7 +758,6 @@ describe 'Taggable' do
|
|
743
758
|
|
744
759
|
context 'Model.limit(x).tag_counts.sum(:tags_count)' do
|
745
760
|
it 'should not break on Mysql' do
|
746
|
-
# Activerecord 3.2 return a string
|
747
761
|
expect(TaggableModel.limit(2).tag_counts.sum('tags_count').to_i).to eq(5)
|
748
762
|
end
|
749
763
|
end
|
@@ -49,15 +49,69 @@ describe ActsAsTaggableOn::Tagging do
|
|
49
49
|
ActsAsTaggableOn.remove_unused_tags = previous_setting
|
50
50
|
end
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
52
|
+
describe 'context scopes' do
|
53
|
+
before do
|
54
|
+
@tagging_2 = ActsAsTaggableOn::Tagging.new
|
55
|
+
@tagging_3 = ActsAsTaggableOn::Tagging.new
|
56
|
+
|
57
|
+
@tagger = User.new
|
58
|
+
@tagger_2 = User.new
|
59
|
+
|
60
|
+
@tagging.taggable = TaggableModel.create(name: "Black holes")
|
61
|
+
@tagging.tag = ActsAsTaggableOn::Tag.create(name: "Physics")
|
62
|
+
@tagging.tagger = @tagger
|
63
|
+
@tagging.context = 'Science'
|
64
|
+
@tagging.save
|
65
|
+
|
66
|
+
@tagging_2.taggable = TaggableModel.create(name: "Satellites")
|
67
|
+
@tagging_2.tag = ActsAsTaggableOn::Tag.create(name: "Technology")
|
68
|
+
@tagging_2.tagger = @tagger_2
|
69
|
+
@tagging_2.context = 'Science'
|
70
|
+
@tagging_2.save
|
71
|
+
|
72
|
+
@tagging_3.taggable = TaggableModel.create(name: "Satellites")
|
73
|
+
@tagging_3.tag = ActsAsTaggableOn::Tag.create(name: "Engineering")
|
74
|
+
@tagging_3.tagger = @tagger_2
|
75
|
+
@tagging_3.context = 'Astronomy'
|
76
|
+
@tagging_3.save
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '.owned_by' do
|
81
|
+
it "should belong to a specific user" do
|
82
|
+
expect(ActsAsTaggableOn::Tagging.owned_by(@tagger).first).to eq(@tagging)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '.by_context' do
|
87
|
+
it "should be found by context" do
|
88
|
+
expect(ActsAsTaggableOn::Tagging.by_context('Science').length).to eq(2);
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '.by_contexts' do
|
93
|
+
it "should find taggings by contexts" do
|
94
|
+
expect(ActsAsTaggableOn::Tagging.by_contexts(['Science', 'Astronomy']).first).to eq(@tagging);
|
95
|
+
expect(ActsAsTaggableOn::Tagging.by_contexts(['Science', 'Astronomy']).second).to eq(@tagging_2);
|
96
|
+
expect(ActsAsTaggableOn::Tagging.by_contexts(['Science', 'Astronomy']).third).to eq(@tagging_3);
|
97
|
+
expect(ActsAsTaggableOn::Tagging.by_contexts(['Science', 'Astronomy']).length).to eq(3);
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '.not_owned' do
|
102
|
+
before do
|
103
|
+
@tagging_4 = ActsAsTaggableOn::Tagging.new
|
104
|
+
@tagging_4.taggable = TaggableModel.create(name: "Gravity")
|
105
|
+
@tagging_4.tag = ActsAsTaggableOn::Tag.create(name: "Space")
|
106
|
+
@tagging_4.context = "Science"
|
107
|
+
@tagging_4.save
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should found the taggings that do not have owner" do
|
111
|
+
expect(ActsAsTaggableOn::Tagging.all.length).to eq(4)
|
112
|
+
expect(ActsAsTaggableOn::Tagging.not_owned.length).to eq(1)
|
113
|
+
expect(ActsAsTaggableOn::Tagging.not_owned.first).to eq(@tagging_4)
|
114
|
+
end
|
115
|
+
end
|
61
116
|
end
|
62
|
-
|
63
117
|
end
|
data/spec/internal/db/schema.rb
CHANGED
@@ -7,12 +7,15 @@ ActiveRecord::Schema.define version: 0 do
|
|
7
7
|
add_index 'tags', ['name'], name: 'index_tags_on_name', unique: true
|
8
8
|
|
9
9
|
create_table :taggings, force: true do |t|
|
10
|
-
t.
|
10
|
+
t.integer :tag_id
|
11
11
|
|
12
12
|
# You should make sure that the column created is
|
13
13
|
# long enough to store the required class names.
|
14
|
-
t.
|
15
|
-
t.
|
14
|
+
t.string :taggable_type
|
15
|
+
t.integer :taggable_id
|
16
|
+
|
17
|
+
t.string :tagger_type
|
18
|
+
t.integer :tagger_id
|
16
19
|
|
17
20
|
# Limit is created to prevent MySQL error on index
|
18
21
|
# length for MyISAM table type: http://bit.ly/vgW2Ql
|
@@ -23,6 +26,7 @@ ActiveRecord::Schema.define version: 0 do
|
|
23
26
|
add_index 'taggings',
|
24
27
|
['tag_id', 'taggable_id', 'taggable_type', 'context', 'tagger_id', 'tagger_type'],
|
25
28
|
unique: true, name: 'taggings_idx'
|
29
|
+
add_index 'taggings', :tag_id , name: 'index_taggings_on_tag_id'
|
26
30
|
|
27
31
|
# above copied from
|
28
32
|
# generators/acts_as_taggable_on/migration/migration_generator
|
data/spec/support/database.rb
CHANGED
@@ -13,13 +13,7 @@ if File.exist?(database_yml)
|
|
13
13
|
config = ActiveRecord::Base.configurations[db_name]
|
14
14
|
|
15
15
|
begin
|
16
|
-
|
17
|
-
#TODO, remove when activerecord 3 support is dropped
|
18
|
-
if ActsAsTaggableOn::Utils.active_record4?
|
19
|
-
ActiveRecord::Base.establish_connection(db_name.to_sym)
|
20
|
-
else
|
21
|
-
ActiveRecord::Base.establish_connection(db_name)
|
22
|
-
end
|
16
|
+
ActiveRecord::Base.establish_connection(db_name.to_sym)
|
23
17
|
ActiveRecord::Base.connection
|
24
18
|
rescue
|
25
19
|
case db_name
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts-as-taggable-on
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Bleigh
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-07-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -17,20 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
21
|
-
- - "<"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: '5'
|
20
|
+
version: '4.0'
|
24
21
|
type: :runtime
|
25
22
|
prerelease: false
|
26
23
|
version_requirements: !ruby/object:Gem::Requirement
|
27
24
|
requirements:
|
28
25
|
- - ">="
|
29
26
|
- !ruby/object:Gem::Version
|
30
|
-
version: '
|
31
|
-
- - "<"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '5'
|
27
|
+
version: '4.0'
|
34
28
|
- !ruby/object:Gem::Dependency
|
35
29
|
name: sqlite3
|
36
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -51,14 +45,14 @@ dependencies:
|
|
51
45
|
requirements:
|
52
46
|
- - "~>"
|
53
47
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.3
|
48
|
+
version: '0.3'
|
55
49
|
type: :development
|
56
50
|
prerelease: false
|
57
51
|
version_requirements: !ruby/object:Gem::Requirement
|
58
52
|
requirements:
|
59
53
|
- - "~>"
|
60
54
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.3
|
55
|
+
version: '0.3'
|
62
56
|
- !ruby/object:Gem::Dependency
|
63
57
|
name: pg
|
64
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -170,19 +164,18 @@ files:
|
|
170
164
|
- db/migrate/3_add_taggings_counter_cache_to_tags.rb
|
171
165
|
- db/migrate/4_add_missing_taggable_index.rb
|
172
166
|
- db/migrate/5_change_collation_for_tag_names.rb
|
173
|
-
-
|
167
|
+
- db/migrate/6_add_missing_indexes.rb
|
174
168
|
- gemfiles/activerecord_4.0.gemfile
|
175
169
|
- gemfiles/activerecord_4.1.gemfile
|
176
170
|
- gemfiles/activerecord_4.2.gemfile
|
171
|
+
- gemfiles/activerecord_5.0.gemfile
|
177
172
|
- lib/acts-as-taggable-on.rb
|
178
173
|
- lib/acts_as_taggable_on.rb
|
179
|
-
- lib/acts_as_taggable_on/compatibility.rb
|
180
174
|
- lib/acts_as_taggable_on/default_parser.rb
|
181
175
|
- lib/acts_as_taggable_on/engine.rb
|
182
176
|
- lib/acts_as_taggable_on/generic_parser.rb
|
183
177
|
- lib/acts_as_taggable_on/tag.rb
|
184
178
|
- lib/acts_as_taggable_on/tag_list.rb
|
185
|
-
- lib/acts_as_taggable_on/tag_list_parser.rb
|
186
179
|
- lib/acts_as_taggable_on/taggable.rb
|
187
180
|
- lib/acts_as_taggable_on/taggable/cache.rb
|
188
181
|
- lib/acts_as_taggable_on/taggable/collection.rb
|
@@ -203,7 +196,6 @@ files:
|
|
203
196
|
- spec/acts_as_taggable_on/generic_parser_spec.rb
|
204
197
|
- spec/acts_as_taggable_on/related_spec.rb
|
205
198
|
- spec/acts_as_taggable_on/single_table_inheritance_spec.rb
|
206
|
-
- spec/acts_as_taggable_on/tag_list_parser_spec.rb
|
207
199
|
- spec/acts_as_taggable_on/tag_list_spec.rb
|
208
200
|
- spec/acts_as_taggable_on/tag_spec.rb
|
209
201
|
- spec/acts_as_taggable_on/taggable/dirty_spec.rb
|
@@ -254,15 +246,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
254
246
|
requirements:
|
255
247
|
- - ">="
|
256
248
|
- !ruby/object:Gem::Version
|
257
|
-
version:
|
249
|
+
version: 2.0.0
|
258
250
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
259
251
|
requirements:
|
260
|
-
- - "
|
252
|
+
- - ">"
|
261
253
|
- !ruby/object:Gem::Version
|
262
|
-
version:
|
254
|
+
version: 1.3.1
|
263
255
|
requirements: []
|
264
256
|
rubyforge_project:
|
265
|
-
rubygems_version: 2.4.5
|
257
|
+
rubygems_version: 2.4.5.1
|
266
258
|
signing_key:
|
267
259
|
specification_version: 4
|
268
260
|
summary: Advanced tagging for Rails.
|
@@ -274,7 +266,6 @@ test_files:
|
|
274
266
|
- spec/acts_as_taggable_on/generic_parser_spec.rb
|
275
267
|
- spec/acts_as_taggable_on/related_spec.rb
|
276
268
|
- spec/acts_as_taggable_on/single_table_inheritance_spec.rb
|
277
|
-
- spec/acts_as_taggable_on/tag_list_parser_spec.rb
|
278
269
|
- spec/acts_as_taggable_on/tag_list_spec.rb
|
279
270
|
- spec/acts_as_taggable_on/tag_spec.rb
|
280
271
|
- spec/acts_as_taggable_on/taggable/dirty_spec.rb
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module ActsAsTaggableOn::Compatibility
|
2
|
-
def has_many_with_taggable_compatibility(name, options = {}, &extention)
|
3
|
-
if ActsAsTaggableOn::Utils.active_record4?
|
4
|
-
scope, opts = build_taggable_scope_and_options(options)
|
5
|
-
has_many(name, scope, opts, &extention)
|
6
|
-
else
|
7
|
-
has_many(name, options, &extention)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def build_taggable_scope_and_options(opts)
|
12
|
-
scope_opts, opts = parse_taggable_options(opts)
|
13
|
-
|
14
|
-
unless scope_opts.empty?
|
15
|
-
scope = -> {
|
16
|
-
scope_opts.inject(self) { |result, hash| result.send(*hash) }
|
17
|
-
}
|
18
|
-
return [scope, opts]
|
19
|
-
end
|
20
|
-
|
21
|
-
[nil, opts]
|
22
|
-
end
|
23
|
-
|
24
|
-
def parse_taggable_options(opts)
|
25
|
-
scope_opts = {}
|
26
|
-
[:order, :having, :select, :group, :limit, :offset, :readonly].each do |o|
|
27
|
-
scope_opts[o] = opts.delete o if opts[o]
|
28
|
-
end
|
29
|
-
scope_opts[:where] = opts.delete :conditions if opts[:conditions]
|
30
|
-
scope_opts[:joins] = opts.delete :include if opts [:include]
|
31
|
-
scope_opts[:distinct] = opts.delete :uniq if opts[:uniq]
|
32
|
-
|
33
|
-
[scope_opts, opts]
|
34
|
-
end
|
35
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module ActsAsTaggableOn
|
2
|
-
##
|
3
|
-
# Returns a new TagList using the given tag string.
|
4
|
-
#
|
5
|
-
# Example:
|
6
|
-
# tag_list = ActsAsTaggableOn::TagListParser.parse("One , Two, Three")
|
7
|
-
# tag_list # ["One", "Two", "Three"]
|
8
|
-
module TagListParser
|
9
|
-
class << self
|
10
|
-
## DEPRECATED
|
11
|
-
def parse(string)
|
12
|
-
ActiveRecord::Base.logger.warn <<WARNING
|
13
|
-
ActsAsTaggableOn::TagListParser.parse is deprecated \
|
14
|
-
and will be removed from v4.0+, use \
|
15
|
-
ActsAsTaggableOn::TagListParser.new instead
|
16
|
-
WARNING
|
17
|
-
DefaultParser.new(string).parse
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# -*- encoding : utf-8 -*-
|
2
|
-
require 'spec_helper'
|
3
|
-
|
4
|
-
describe ActsAsTaggableOn::TagListParser do
|
5
|
-
it '#parse should return empty array if empty array is passed' do
|
6
|
-
expect(ActsAsTaggableOn::TagListParser.parse([])).to be_empty
|
7
|
-
end
|
8
|
-
|
9
|
-
describe 'Multiple Delimiter' do
|
10
|
-
before do
|
11
|
-
@old_delimiter = ActsAsTaggableOn.delimiter
|
12
|
-
end
|
13
|
-
|
14
|
-
after do
|
15
|
-
ActsAsTaggableOn.delimiter = @old_delimiter
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should separate tags by delimiters' do
|
19
|
-
ActsAsTaggableOn.delimiter = [',', ' ', '\|']
|
20
|
-
tag_list = ActsAsTaggableOn::TagListParser.parse('cool, data|I have')
|
21
|
-
expect(tag_list.to_s).to eq('cool, data, I, have')
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'should escape quote' do
|
25
|
-
ActsAsTaggableOn.delimiter = [',', ' ', '\|']
|
26
|
-
tag_list = ActsAsTaggableOn::TagListParser.parse "'I have'|cool, data"
|
27
|
-
expect(tag_list.to_s).to eq('"I have", cool, data')
|
28
|
-
|
29
|
-
tag_list = ActsAsTaggableOn::TagListParser.parse '"I, have"|cool, data'
|
30
|
-
expect(tag_list.to_s).to eq('"I, have", cool, data')
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should work for utf8 delimiter and long delimiter' do
|
34
|
-
ActsAsTaggableOn.delimiter = [',', '的', '可能是']
|
35
|
-
tag_list = ActsAsTaggableOn::TagListParser.parse('我的东西可能是不见了,还好有备份')
|
36
|
-
expect(tag_list.to_s).to eq('我, 东西, 不见了, 还好有备份')
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'should work for multiple quoted tags' do
|
40
|
-
ActsAsTaggableOn.delimiter = [',']
|
41
|
-
tag_list = ActsAsTaggableOn::TagListParser.parse('"Ruby Monsters","eat Katzenzungen"')
|
42
|
-
expect(tag_list.to_s).to eq('Ruby Monsters, eat Katzenzungen')
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|