acts-as-taggable-on 3.2.3 → 3.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +8 -7
- data/Gemfile +0 -1
- data/acts-as-taggable-on.gemspec +6 -7
- data/gemfiles/activerecord_3.2.gemfile +0 -1
- data/gemfiles/activerecord_4.0.gemfile +0 -1
- data/gemfiles/activerecord_4.1.gemfile +0 -1
- data/gemfiles/activerecord_edge.gemfile +0 -1
- data/lib/acts-as-taggable-on.rb +28 -20
- data/lib/acts_as_taggable_on/tag_list.rb +13 -77
- data/lib/acts_as_taggable_on/tag_list_parser.rb +78 -0
- data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/core.rb +14 -10
- data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/ownership.rb +1 -1
- data/lib/acts_as_taggable_on/taggable.rb +7 -6
- data/lib/acts_as_taggable_on/utils.rb +2 -26
- data/lib/acts_as_taggable_on/version.rb +1 -1
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +1 -1
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +1 -0
- data/spec/acts_as_taggable_on/caching_spec.rb +1 -0
- data/spec/acts_as_taggable_on/related_spec.rb +1 -0
- data/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +1 -0
- data/spec/acts_as_taggable_on/tag_list_parser_spec.rb +46 -0
- data/spec/acts_as_taggable_on/tag_list_spec.rb +3 -40
- data/spec/acts_as_taggable_on/tag_spec.rb +29 -35
- data/spec/acts_as_taggable_on/taggable_spec.rb +55 -55
- data/spec/acts_as_taggable_on/tagger_spec.rb +1 -0
- data/spec/acts_as_taggable_on/tagging_spec.rb +2 -1
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +1 -0
- data/spec/acts_as_taggable_on/utils_spec.rb +1 -0
- data/spec/internal/app/models/cached_model_with_array.rb +1 -1
- data/spec/internal/app/models/models.rb +2 -2
- data/spec/internal/db/schema.rb +2 -2
- data/spec/spec_helper.rb +0 -1
- data/spec/support/0-helpers.rb +32 -0
- metadata +36 -47
- data/spec/schema.rb +0 -82
- /data/lib/acts_as_taggable_on/{acts_as_taggable_on/compatibility.rb → compatibility.rb} +0 -0
- /data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/cache.rb +0 -0
- /data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/collection.rb +0 -0
- /data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/dirty.rb +0 -0
- /data/lib/acts_as_taggable_on/{acts_as_taggable_on → taggable}/related.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a20675bbbf6a845a9af63de544fd91aa3d0456c4
|
|
4
|
+
data.tar.gz: 525532eb66d8245b5d5e5f5e0b0bcafbd71f0165
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: da3437561dbcb861750489d2abcff557bd2aa488a483ea73d242a51d08fa6df6be4b8a64b1f7fbbed9e3dd44ea63e9b7b6101bd4d52d5a0ee05658272d16e5d8
|
|
7
|
+
data.tar.gz: 4f34e61243d64b0f77c842dc929c3dc6e1039b65a388d0da2e0b31484b7c63637acc76764dc18c5fde11198199dcf5756460b322e38abd5cbb9a65ed1a510c1d
|
data/.travis.yml
CHANGED
|
@@ -25,18 +25,19 @@ matrix:
|
|
|
25
25
|
allow_failures:
|
|
26
26
|
- gemfile: gemfiles/activerecord_edge.gemfile
|
|
27
27
|
- rvm: rbx-2
|
|
28
|
+
- rvm: ruby-head
|
|
28
29
|
exclude:
|
|
29
30
|
- rvm: 1.9.3
|
|
30
|
-
gemfile:
|
|
31
|
+
gemfile: gemfiles/activerecord_4.0.gemfile
|
|
31
32
|
- rvm: 1.9.3
|
|
32
|
-
gemfile:
|
|
33
|
+
gemfile: gemfiles/activerecord_4.1.gemfile
|
|
33
34
|
- rvm: 1.9.3
|
|
34
|
-
gemfile:
|
|
35
|
+
gemfile: gemfiles/activerecord_edge.gemfile
|
|
35
36
|
- rvm: rbx-2
|
|
36
|
-
gemfile:
|
|
37
|
+
gemfile: gemfiles/activerecord_3.2.gemfile
|
|
37
38
|
- rvm: ruby-head
|
|
38
|
-
gemfile:
|
|
39
|
+
gemfile: gemfiles/activerecord_3.2.gemfile
|
|
39
40
|
- rvm: ruby-head
|
|
40
|
-
gemfile:
|
|
41
|
+
gemfile: gemfiles/activerecord_4.0.gemfile
|
|
41
42
|
- rvm: ruby-head
|
|
42
|
-
gemfile:
|
|
43
|
+
gemfile: gemfiles/activerecord_4.1.gemfile
|
data/Gemfile
CHANGED
data/acts-as-taggable-on.gemspec
CHANGED
|
@@ -26,13 +26,12 @@ Gem::Specification.new do |gem|
|
|
|
26
26
|
gem.add_runtime_dependency 'actionpack', ['>= 3', '< 5']
|
|
27
27
|
|
|
28
28
|
gem.add_development_dependency 'sqlite3'
|
|
29
|
-
gem.add_development_dependency 'mysql2'
|
|
29
|
+
gem.add_development_dependency 'mysql2', '~> 0.3.7'
|
|
30
30
|
gem.add_development_dependency 'pg'
|
|
31
31
|
|
|
32
|
-
gem.add_development_dependency 'rspec-rails' , '~> 3.0.0.
|
|
33
|
-
gem.add_development_dependency 'rspec-its'
|
|
34
|
-
gem.add_development_dependency 'rspec'
|
|
35
|
-
gem.add_development_dependency '
|
|
36
|
-
gem.add_development_dependency '
|
|
37
|
-
gem.add_development_dependency 'database_cleaner', '~> 1.2'
|
|
32
|
+
gem.add_development_dependency 'rspec-rails' , '~> 3.0.0.beta'
|
|
33
|
+
gem.add_development_dependency 'rspec-its'
|
|
34
|
+
gem.add_development_dependency 'rspec'
|
|
35
|
+
gem.add_development_dependency 'barrier'
|
|
36
|
+
gem.add_development_dependency 'database_cleaner'
|
|
38
37
|
end
|
data/lib/acts-as-taggable-on.rb
CHANGED
|
@@ -3,9 +3,35 @@ require 'active_record/version'
|
|
|
3
3
|
require 'active_support/core_ext/module'
|
|
4
4
|
require 'action_view'
|
|
5
5
|
|
|
6
|
+
require_relative 'acts_as_taggable_on/engine'
|
|
7
|
+
|
|
6
8
|
require 'digest/sha1'
|
|
7
9
|
|
|
8
10
|
module ActsAsTaggableOn
|
|
11
|
+
extend ActiveSupport::Autoload
|
|
12
|
+
|
|
13
|
+
autoload :Tag
|
|
14
|
+
autoload :TagList
|
|
15
|
+
autoload :TagListParser
|
|
16
|
+
autoload :Taggable
|
|
17
|
+
autoload :Tagger
|
|
18
|
+
autoload :Tagging
|
|
19
|
+
autoload :TagsHelper
|
|
20
|
+
autoload :VERSION
|
|
21
|
+
|
|
22
|
+
autoload_under 'taggable' do
|
|
23
|
+
autoload :Cache
|
|
24
|
+
autoload :Collection
|
|
25
|
+
autoload :Core
|
|
26
|
+
autoload :Dirty
|
|
27
|
+
autoload :Ownership
|
|
28
|
+
autoload :Related
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
autoload :Utils
|
|
32
|
+
autoload :Compatibility
|
|
33
|
+
|
|
34
|
+
|
|
9
35
|
class DuplicateTagError < StandardError
|
|
10
36
|
end
|
|
11
37
|
|
|
@@ -16,7 +42,7 @@ module ActsAsTaggableOn
|
|
|
16
42
|
|
|
17
43
|
def self.method_missing(method_name, *args, &block)
|
|
18
44
|
@configuration.respond_to?(method_name) ?
|
|
19
|
-
|
|
45
|
+
@configuration.send(method_name, *args, &block) : super
|
|
20
46
|
end
|
|
21
47
|
|
|
22
48
|
def self.respond_to?(method_name, include_private=false)
|
|
@@ -31,7 +57,7 @@ module ActsAsTaggableOn
|
|
|
31
57
|
|
|
32
58
|
class Configuration
|
|
33
59
|
attr_accessor :delimiter, :force_lowercase, :force_parameterize,
|
|
34
|
-
|
|
60
|
+
:strict_case_match, :remove_unused_tags
|
|
35
61
|
|
|
36
62
|
def initialize
|
|
37
63
|
@delimiter = ','
|
|
@@ -45,24 +71,6 @@ module ActsAsTaggableOn
|
|
|
45
71
|
setup
|
|
46
72
|
end
|
|
47
73
|
|
|
48
|
-
require 'acts_as_taggable_on/utils'
|
|
49
|
-
|
|
50
|
-
require 'acts_as_taggable_on/taggable'
|
|
51
|
-
require 'acts_as_taggable_on/acts_as_taggable_on/compatibility'
|
|
52
|
-
require 'acts_as_taggable_on/acts_as_taggable_on/core'
|
|
53
|
-
require 'acts_as_taggable_on/acts_as_taggable_on/collection'
|
|
54
|
-
require 'acts_as_taggable_on/acts_as_taggable_on/cache'
|
|
55
|
-
require 'acts_as_taggable_on/acts_as_taggable_on/ownership'
|
|
56
|
-
require 'acts_as_taggable_on/acts_as_taggable_on/related'
|
|
57
|
-
require 'acts_as_taggable_on/acts_as_taggable_on/dirty'
|
|
58
|
-
|
|
59
|
-
require 'acts_as_taggable_on/tagger'
|
|
60
|
-
require 'acts_as_taggable_on/tag'
|
|
61
|
-
require 'acts_as_taggable_on/tag_list'
|
|
62
|
-
require 'acts_as_taggable_on/tags_helper'
|
|
63
|
-
require 'acts_as_taggable_on/tagging'
|
|
64
|
-
require 'acts_as_taggable_on/engine'
|
|
65
|
-
|
|
66
74
|
ActiveSupport.on_load(:active_record) do
|
|
67
75
|
extend ActsAsTaggableOn::Compatibility
|
|
68
76
|
extend ActsAsTaggableOn::Taggable
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
require 'active_support/core_ext/module/delegation'
|
|
2
3
|
|
|
3
4
|
module ActsAsTaggableOn
|
|
@@ -8,82 +9,6 @@ module ActsAsTaggableOn
|
|
|
8
9
|
add(*args)
|
|
9
10
|
end
|
|
10
11
|
|
|
11
|
-
class << self
|
|
12
|
-
##
|
|
13
|
-
# Returns a new TagList using the given tag string.
|
|
14
|
-
#
|
|
15
|
-
# Example:
|
|
16
|
-
# tag_list = ActsAsTaggableOn::TagList.from("One , Two, Three")
|
|
17
|
-
# tag_list # ["One", "Two", "Three"]
|
|
18
|
-
def from(string)
|
|
19
|
-
string = string.join(ActsAsTaggableOn.glue) if string.respond_to?(:join)
|
|
20
|
-
|
|
21
|
-
new.tap do |tag_list|
|
|
22
|
-
string = string.to_s.dup
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
string.gsub!(double_quote_pattern) {
|
|
26
|
-
# Append the matched tag to the tag list
|
|
27
|
-
tag_list << Regexp.last_match[2]
|
|
28
|
-
# Return the matched delimiter ($3) to replace the matched items
|
|
29
|
-
''
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
string.gsub!(single_quote_pattern) {
|
|
33
|
-
# Append the matched tag ($2) to the tag list
|
|
34
|
-
tag_list << Regexp.last_match[2]
|
|
35
|
-
# Return an empty string to replace the matched items
|
|
36
|
-
''
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
# split the string by the delimiter
|
|
40
|
-
# and add to the tag_list
|
|
41
|
-
tag_list.add(string.split(Regexp.new delimiter))
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def delimiter
|
|
46
|
-
# Parse the quoted tags
|
|
47
|
-
d = ActsAsTaggableOn.delimiter
|
|
48
|
-
# Separate multiple delimiters by bitwise operator
|
|
49
|
-
d = d.join('|') if d.kind_of?(Array)
|
|
50
|
-
|
|
51
|
-
d
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def single_quote_pattern
|
|
55
|
-
%r{
|
|
56
|
-
( # Tag start delimiter ($1)
|
|
57
|
-
\A | # Either string start or
|
|
58
|
-
#{delimiter} # a delimiter
|
|
59
|
-
)
|
|
60
|
-
\s*' # quote (') optionally preceded by whitespace
|
|
61
|
-
(.*?) # Tag ($2)
|
|
62
|
-
'\s* # quote (') optionally followed by whitespace
|
|
63
|
-
(?= # Tag end delimiter (not consumed; is zero-length lookahead)
|
|
64
|
-
#{delimiter}\s* | # Either a delimiter optionally followed by whitespace or
|
|
65
|
-
\z # string end
|
|
66
|
-
)
|
|
67
|
-
}x
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def double_quote_pattern
|
|
71
|
-
%r{
|
|
72
|
-
( # Tag start delimiter ($1)
|
|
73
|
-
\A | # Either string start or
|
|
74
|
-
#{delimiter} # a delimiter
|
|
75
|
-
)
|
|
76
|
-
\s*" # quote (") optionally preceded by whitespace
|
|
77
|
-
(.*?) # Tag ($2)
|
|
78
|
-
"\s* # quote (") optionally followed by whitespace
|
|
79
|
-
(?= # Tag end delimiter (not consumed; is zero-length lookahead)
|
|
80
|
-
#{delimiter}\s* | # Either a delimiter optionally followed by whitespace or
|
|
81
|
-
\z # string end
|
|
82
|
-
)
|
|
83
|
-
}x
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
end
|
|
87
12
|
##
|
|
88
13
|
# Add tags to the tag_list. Duplicate or blank tags will be ignored.
|
|
89
14
|
# Use the <tt>:parse</tt> option to add an unparsed tag string.
|
|
@@ -165,12 +90,23 @@ module ActsAsTaggableOn
|
|
|
165
90
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
166
91
|
options.assert_valid_keys :parse
|
|
167
92
|
|
|
168
|
-
args.map! { |a|
|
|
93
|
+
args.map! { |a| TagListParser.parse(a) } if options[:parse]
|
|
169
94
|
|
|
170
95
|
args.flatten!
|
|
171
96
|
end
|
|
172
97
|
|
|
173
98
|
|
|
99
|
+
## DEPRECATED
|
|
100
|
+
def self.from(string)
|
|
101
|
+
ActiveRecord::Base.logger.warn <<WARNING
|
|
102
|
+
ActsAsTaggableOn::TagList.from is deprecated \
|
|
103
|
+
and will be removed from v4.0+, use \
|
|
104
|
+
ActsAsTaggableOn::TagListParser.parse instead
|
|
105
|
+
WARNING
|
|
106
|
+
TagListParser.parse(string)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
174
110
|
end
|
|
175
111
|
end
|
|
176
112
|
|
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
def parse(string)
|
|
11
|
+
string = string.join(ActsAsTaggableOn.glue) if string.respond_to?(:join)
|
|
12
|
+
TagList.new.tap do |tag_list|
|
|
13
|
+
string = string.to_s.dup
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
string.gsub!(double_quote_pattern) {
|
|
17
|
+
# Append the matched tag to the tag list
|
|
18
|
+
tag_list << Regexp.last_match[2]
|
|
19
|
+
# Return the matched delimiter ($3) to replace the matched items
|
|
20
|
+
''
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
string.gsub!(single_quote_pattern) {
|
|
24
|
+
# Append the matched tag ($2) to the tag list
|
|
25
|
+
tag_list << Regexp.last_match[2]
|
|
26
|
+
# Return an empty string to replace the matched items
|
|
27
|
+
''
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# split the string by the delimiter
|
|
31
|
+
# and add to the tag_list
|
|
32
|
+
tag_list.add(string.split(Regexp.new delimiter))
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# private
|
|
38
|
+
def delimiter
|
|
39
|
+
# Parse the quoted tags
|
|
40
|
+
d = ActsAsTaggableOn.delimiter
|
|
41
|
+
# Separate multiple delimiters by bitwise operator
|
|
42
|
+
d = d.join('|') if d.kind_of?(Array)
|
|
43
|
+
d
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# ( # Tag start delimiter ($1)
|
|
47
|
+
# \A | # Either string start or
|
|
48
|
+
# #{delimiter} # a delimiter
|
|
49
|
+
# )
|
|
50
|
+
# \s*" # quote (") optionally preceded by whitespace
|
|
51
|
+
# (.*?) # Tag ($2)
|
|
52
|
+
# "\s* # quote (") optionally followed by whitespace
|
|
53
|
+
# (?= # Tag end delimiter (not consumed; is zero-length lookahead)
|
|
54
|
+
# #{delimiter}\s* | # Either a delimiter optionally followed by whitespace or
|
|
55
|
+
# \z # string end
|
|
56
|
+
# )
|
|
57
|
+
def double_quote_pattern
|
|
58
|
+
/(\A|#{delimiter})\s*"(.*?)"\s*(?=#{delimiter}\s*|\z)/
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# ( # Tag start delimiter ($1)
|
|
62
|
+
# \A | # Either string start or
|
|
63
|
+
# #{delimiter} # a delimiter
|
|
64
|
+
# )
|
|
65
|
+
# \s*' # quote (') optionally preceded by whitespace
|
|
66
|
+
# (.*?) # Tag ($2)
|
|
67
|
+
# '\s* # quote (') optionally followed by whitespace
|
|
68
|
+
# (?= # Tag end delimiter (not consumed; is zero-length lookahead)
|
|
69
|
+
# #{delimiter}\s* | d # Either a delimiter optionally followed by whitespace or
|
|
70
|
+
# \z # string end
|
|
71
|
+
# )
|
|
72
|
+
def single_quote_pattern
|
|
73
|
+
/(\A|#{delimiter})\s*'(.*?)'\s*(?=#{delimiter}\s*|\z)/
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -82,7 +82,7 @@ module ActsAsTaggableOn::Taggable
|
|
|
82
82
|
# User.tagged_with("awesome", "cool", :match_all => true) # Users that are tagged with just awesome and cool
|
|
83
83
|
# User.tagged_with("awesome", "cool", :owned_by => foo ) # Users that are tagged with just awesome and cool by 'foo'
|
|
84
84
|
def tagged_with(tags, options = {})
|
|
85
|
-
tag_list = ActsAsTaggableOn::
|
|
85
|
+
tag_list = ActsAsTaggableOn::TagListParser.parse(tags)
|
|
86
86
|
options = options.dup
|
|
87
87
|
empty_result = where('1 = 0')
|
|
88
88
|
|
|
@@ -116,7 +116,7 @@ module ActsAsTaggableOn::Taggable
|
|
|
116
116
|
" AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = #{quote_value(owned_by.class.base_class.to_s, nil)}"
|
|
117
117
|
end
|
|
118
118
|
|
|
119
|
-
elsif options.delete(:any)
|
|
119
|
+
elsif any = options.delete(:any)
|
|
120
120
|
# get tags, drop out if nothing returned (we need at least one)
|
|
121
121
|
tags = if options.delete(:wild)
|
|
122
122
|
ActsAsTaggableOn::Tag.named_like_any(tag_list)
|
|
@@ -141,7 +141,7 @@ module ActsAsTaggableOn::Taggable
|
|
|
141
141
|
|
|
142
142
|
# don't need to sanitize sql, map all ids and join with OR logic
|
|
143
143
|
conditions << tags.map { |t| "#{taggings_alias}.tag_id = #{quote_value(t.id, nil)}" }.join(' OR ')
|
|
144
|
-
select_clause
|
|
144
|
+
select_clause << " #{table_name}.*" unless context and tag_types.one?
|
|
145
145
|
|
|
146
146
|
if owned_by
|
|
147
147
|
tagging_join << ' AND ' +
|
|
@@ -153,7 +153,10 @@ module ActsAsTaggableOn::Taggable
|
|
|
153
153
|
end
|
|
154
154
|
|
|
155
155
|
joins << tagging_join
|
|
156
|
-
|
|
156
|
+
unless any == 'distinct' # Fix issue #544
|
|
157
|
+
group = "#{table_name}.#{primary_key}"
|
|
158
|
+
select_clause << group
|
|
159
|
+
end
|
|
157
160
|
else
|
|
158
161
|
tags = ActsAsTaggableOn::Tag.named_any(tag_list)
|
|
159
162
|
|
|
@@ -183,7 +186,7 @@ module ActsAsTaggableOn::Taggable
|
|
|
183
186
|
|
|
184
187
|
group ||= [] # Rails interprets this as a no-op in the group() call below
|
|
185
188
|
if options.delete(:order_by_matching_tag_count)
|
|
186
|
-
select_clause
|
|
189
|
+
select_clause << "#{table_name}.*, COUNT(#{taggings_alias}.tag_id) AS #{taggings_alias}_count"
|
|
187
190
|
group_columns = ActsAsTaggableOn::Utils.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}"
|
|
188
191
|
group = group_columns
|
|
189
192
|
order_by << "#{taggings_alias}_count DESC"
|
|
@@ -203,8 +206,9 @@ module ActsAsTaggableOn::Taggable
|
|
|
203
206
|
|
|
204
207
|
order_by << options[:order] if options[:order].present?
|
|
205
208
|
|
|
206
|
-
|
|
207
|
-
.
|
|
209
|
+
query = self
|
|
210
|
+
query = self.select(select_clause.join(',')) unless select_clause.empty?
|
|
211
|
+
query.joins(joins.join(' '))
|
|
208
212
|
.where(conditions.join(' AND '))
|
|
209
213
|
.group(group)
|
|
210
214
|
.having(having)
|
|
@@ -259,7 +263,7 @@ module ActsAsTaggableOn::Taggable
|
|
|
259
263
|
if instance_variable_get(variable_name)
|
|
260
264
|
instance_variable_get(variable_name)
|
|
261
265
|
elsif cached_tag_list_on(context) && self.class.caching_tag_list_on?(context)
|
|
262
|
-
instance_variable_set(variable_name, ActsAsTaggableOn::
|
|
266
|
+
instance_variable_set(variable_name, ActsAsTaggableOn::TagListParser.parse(cached_tag_list_on(context)))
|
|
263
267
|
else
|
|
264
268
|
instance_variable_set(variable_name, ActsAsTaggableOn::TagList.new(tags_on(context).map(&:name)))
|
|
265
269
|
end
|
|
@@ -309,7 +313,7 @@ module ActsAsTaggableOn::Taggable
|
|
|
309
313
|
variable_name = "@#{context.to_s.singularize}_list"
|
|
310
314
|
process_dirty_object(context, new_list) unless custom_contexts.include?(context.to_s)
|
|
311
315
|
|
|
312
|
-
instance_variable_set(variable_name, ActsAsTaggableOn::
|
|
316
|
+
instance_variable_set(variable_name, ActsAsTaggableOn::TagListParser.parse(new_list))
|
|
313
317
|
end
|
|
314
318
|
|
|
315
319
|
def tagging_contexts
|
|
@@ -383,7 +387,7 @@ module ActsAsTaggableOn::Taggable
|
|
|
383
387
|
|
|
384
388
|
# Destroy old taggings:
|
|
385
389
|
if old_tags.present?
|
|
386
|
-
|
|
390
|
+
taggings.not_owned.by_context(context).destroy_all(tag_id: old_tags)
|
|
387
391
|
end
|
|
388
392
|
|
|
389
393
|
# Create new taggings:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
module ActsAsTaggableOn
|
|
2
2
|
module Taggable
|
|
3
|
+
|
|
3
4
|
def taggable?
|
|
4
5
|
false
|
|
5
6
|
end
|
|
@@ -90,12 +91,12 @@ module ActsAsTaggableOn
|
|
|
90
91
|
|
|
91
92
|
# each of these add context-specific methods and must be
|
|
92
93
|
# called on each call of taggable_on
|
|
93
|
-
include
|
|
94
|
-
include
|
|
95
|
-
include
|
|
96
|
-
include
|
|
97
|
-
include
|
|
98
|
-
include
|
|
94
|
+
include Core
|
|
95
|
+
include Collection
|
|
96
|
+
include Cache
|
|
97
|
+
include Ownership
|
|
98
|
+
include Related
|
|
99
|
+
include Dirty
|
|
99
100
|
end
|
|
100
101
|
end
|
|
101
102
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# This module is deprecated and will be removed in the incoming versions
|
|
2
|
+
|
|
1
3
|
module ActsAsTaggableOn
|
|
2
4
|
module Utils
|
|
3
5
|
class << self
|
|
@@ -10,33 +12,11 @@ module ActsAsTaggableOn
|
|
|
10
12
|
connection && connection.adapter_name == 'PostgreSQL'
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
def postgresql_version
|
|
14
|
-
if using_postgresql?
|
|
15
|
-
connection.execute('SHOW SERVER_VERSION').first['server_version'].to_f
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def postgresql_support_json?
|
|
20
|
-
postgresql_version >= 9.2
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def using_sqlite?
|
|
24
|
-
connection && connection.adapter_name == 'SQLite'
|
|
25
|
-
end
|
|
26
|
-
|
|
27
15
|
def using_mysql?
|
|
28
16
|
#We should probably use regex for mysql to support prehistoric adapters
|
|
29
17
|
connection && connection.adapter_name == 'Mysql2'
|
|
30
18
|
end
|
|
31
19
|
|
|
32
|
-
def using_case_insensitive_collation?
|
|
33
|
-
using_mysql? && connection.collation =~ /_ci\Z/
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def supports_concurrency?
|
|
37
|
-
!using_sqlite?
|
|
38
|
-
end
|
|
39
|
-
|
|
40
20
|
def sha_prefix(string)
|
|
41
21
|
Digest::SHA1.hexdigest("#{string}#{rand}")[0..6]
|
|
42
22
|
end
|
|
@@ -45,10 +25,6 @@ module ActsAsTaggableOn
|
|
|
45
25
|
::ActiveRecord::VERSION::MAJOR == 4
|
|
46
26
|
end
|
|
47
27
|
|
|
48
|
-
def active_record42?
|
|
49
|
-
active_record4? && ::ActiveRecord::VERSION::MINOR >= 2
|
|
50
|
-
end
|
|
51
|
-
|
|
52
28
|
def like_operator
|
|
53
29
|
using_postgresql? ? 'ILIKE' : 'LIKE'
|
|
54
30
|
end
|
|
@@ -0,0 +1,46 @@
|
|
|
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
|