acts-as-taggable-on 2.4.0 → 2.4.1
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/.gitignore +1 -1
- data/Appraisals +7 -0
- data/Gemfile +3 -1
- data/{MIT-LICENSE.md → LICENSE.md} +0 -0
- data/README.md +22 -16
- data/Rakefile +2 -2
- data/acts-as-taggable-on.gemspec +22 -19
- data/gemfiles/rails_3.gemfile +8 -0
- data/gemfiles/rails_4.gemfile +8 -0
- data/lib/acts-as-taggable-on.rb +2 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +5 -7
- data/lib/acts_as_taggable_on/acts_as_taggable_on/compatibility.rb +34 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +75 -50
- data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +1 -1
- data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +21 -12
- data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +27 -18
- data/lib/acts_as_taggable_on/tag.rb +8 -8
- data/lib/acts_as_taggable_on/taggable.rb +10 -7
- data/lib/acts_as_taggable_on/tagger.rb +12 -3
- data/lib/acts_as_taggable_on/tagging.rb +2 -2
- data/lib/acts_as_taggable_on/tags_helper.rb +0 -2
- data/lib/{acts-as-taggable-on → acts_as_taggable_on}/version.rb +1 -1
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +1 -216
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +8 -8
- data/spec/acts_as_taggable_on/related_spec.rb +143 -0
- data/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +187 -0
- data/spec/acts_as_taggable_on/tag_list_spec.rb +2 -2
- data/spec/acts_as_taggable_on/tag_spec.rb +3 -4
- data/spec/acts_as_taggable_on/taggable_spec.rb +127 -116
- data/spec/acts_as_taggable_on/tagger_spec.rb +32 -33
- data/spec/acts_as_taggable_on/tagging_spec.rb +1 -1
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +2 -2
- data/spec/acts_as_taggable_on/utils_spec.rb +2 -2
- data/spec/models.rb +2 -2
- data/spec/schema.rb +1 -1
- data/spec/spec_helper.rb +7 -4
- metadata +48 -34
- data/CHANGELOG.md +0 -35
- data/UPGRADING +0 -14
- data/rails/init.rb +0 -1
- data/uninstall.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0b7cd2b4e279238a0fb8464721b40c3dbedaacd
|
4
|
+
data.tar.gz: edd07332dcbd884be1daab9e65d9be28b6f3f695
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65f468a535ce620033df88d152bd5e1bff722c01a197d233794da097e682b29ad5f4ebf46b4eb46a18957d2ecda9f6699aad27b42789a2c8ee8d7c4f68e985ba
|
7
|
+
data.tar.gz: 2fd5249aa31f826fd56666dd3d07c4a63df1803722fc7e29c02b39fdbff6f0459316f30a1bb9345c53e885fa5a0edfd30495e211e8e6e90630600d9d60cd69a5
|
data/.gitignore
CHANGED
data/Appraisals
ADDED
data/Gemfile
CHANGED
File without changes
|
data/README.md
CHANGED
@@ -14,18 +14,28 @@ Enter Acts as Taggable On. Rather than tying functionality to a specific keyword
|
|
14
14
|
tag "contexts" that can be used locally or in combination in the same way steroids
|
15
15
|
was used.
|
16
16
|
|
17
|
-
##
|
17
|
+
## Compatibility
|
18
|
+
|
19
|
+
Versions 2.x are compatible with Ruby 1.8.7+ and Rails 3.
|
20
|
+
|
21
|
+
Versions 2.4.1 and up are compatible with Rails 4 too (thanks to arabonradar and cwoodcox).
|
18
22
|
|
19
|
-
|
23
|
+
Versions 3.x (currently unreleased) are compatible with Ruby 1.9.3+ and Rails 3 and 4.
|
20
24
|
|
21
|
-
|
25
|
+
For an up-to-date roadmap, see https://github.com/mbleigh/acts-as-taggable-on/issues/milestones
|
22
26
|
|
23
|
-
|
27
|
+
## Installation
|
24
28
|
|
25
29
|
To use it, add it to your Gemfile:
|
26
30
|
|
27
31
|
```ruby
|
28
|
-
gem 'acts-as-taggable-on'
|
32
|
+
gem 'acts-as-taggable-on'
|
33
|
+
```
|
34
|
+
|
35
|
+
and bundle:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
bundle
|
29
39
|
```
|
30
40
|
|
31
41
|
#### Post Installation
|
@@ -38,12 +48,15 @@ rake db:migrate
|
|
38
48
|
## Testing
|
39
49
|
|
40
50
|
Acts As Taggable On uses RSpec for its test coverage. Inside the gem
|
41
|
-
directory, you can run the specs
|
51
|
+
directory, you can run the specs with:
|
42
52
|
|
43
53
|
```shell
|
54
|
+
bundle
|
44
55
|
rake spec
|
45
56
|
```
|
46
57
|
|
58
|
+
If you want, add a `.ruby-version` file in the project root (and use rbenv or RVM) to work on a specific version of Ruby.
|
59
|
+
|
47
60
|
## Usage
|
48
61
|
|
49
62
|
```ruby
|
@@ -277,21 +290,14 @@ If you want to change the default delimiter (it defaults to ','). You can also p
|
|
277
290
|
ActsAsTaggableOn.delimiter = ','
|
278
291
|
```
|
279
292
|
|
280
|
-
## Changelog
|
281
|
-
|
282
|
-
See [CHANGELOG](https://github.com/mbleigh/acts-as-taggable-on/blob/master/CHANGELOG.md).
|
283
|
-
|
284
293
|
## Contributors
|
285
294
|
|
286
295
|
We have a long list of valued contributors. [Check them all](https://github.com/mbleigh/acts-as-taggable-on/contributors)
|
287
296
|
|
288
|
-
##
|
297
|
+
## Maintainer
|
289
298
|
|
290
|
-
* [Artem Kramarenko](https://github.com/artemk) (artemk)
|
291
299
|
* [Joost Baaij](https://github.com/tilsammans)
|
292
300
|
|
293
|
-
##
|
294
|
-
|
295
|
-
* [Michael Bleigh](https://github.com/mbleigh)
|
301
|
+
## License
|
296
302
|
|
297
|
-
|
303
|
+
See [LICENSE](https://github.com/mbleigh/acts-as-taggable-on/blob/master/LICENSE.md)
|
data/Rakefile
CHANGED
data/acts-as-taggable-on.gemspec
CHANGED
@@ -1,32 +1,35 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'acts_as_taggable_on/version'
|
3
5
|
|
4
6
|
Gem::Specification.new do |gem|
|
5
|
-
gem.name
|
6
|
-
gem.
|
7
|
-
gem.
|
8
|
-
gem.
|
9
|
-
gem.
|
10
|
-
gem.
|
11
|
-
gem.homepage = ''
|
7
|
+
gem.name = "acts-as-taggable-on"
|
8
|
+
gem.version = ActsAsTaggableOn::VERSION
|
9
|
+
gem.authors = ["Michael Bleigh", "Joost Baaij"]
|
10
|
+
gem.email = ["michael@intridea.com", "joost@spacebabies.nl"]
|
11
|
+
gem.description = %q{With ActsAsTaggableOn, you can tag a single model on several contexts, such as skills, interests, and awards. It also provides other advanced functionality.}
|
12
|
+
gem.summary = "Advanced tagging for Rails."
|
13
|
+
gem.homepage = 'https://github.com/mbleigh/acts-as-taggable-on'
|
14
|
+
gem.license = "MIT"
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.require_paths = ["lib"]
|
12
20
|
|
13
21
|
if File.exists?('UPGRADING')
|
14
|
-
gem.post_install_message = File.read(
|
22
|
+
gem.post_install_message = File.read('UPGRADING')
|
15
23
|
end
|
16
24
|
|
17
|
-
gem.add_runtime_dependency 'rails', '
|
25
|
+
gem.add_runtime_dependency 'rails', ['>= 3', '< 5']
|
26
|
+
|
27
|
+
gem.add_development_dependency 'rspec-rails', '2.13.0' # 2.13.1 is broken
|
18
28
|
gem.add_development_dependency 'rspec', '~> 2.6'
|
19
|
-
gem.add_development_dependency 'ammeter'
|
29
|
+
gem.add_development_dependency 'ammeter'
|
20
30
|
gem.add_development_dependency 'sqlite3'
|
21
31
|
gem.add_development_dependency 'mysql2', '~> 0.3.7'
|
22
32
|
gem.add_development_dependency 'pg'
|
23
33
|
gem.add_development_dependency 'guard'
|
24
34
|
gem.add_development_dependency 'guard-rspec'
|
25
|
-
|
26
|
-
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
27
|
-
gem.files = `git ls-files`.split("\n")
|
28
|
-
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
29
|
-
gem.name = "acts-as-taggable-on"
|
30
|
-
gem.require_paths = ['lib']
|
31
|
-
gem.version = ActsAsTaggableOn::VERSION
|
32
35
|
end
|
data/lib/acts-as-taggable-on.rb
CHANGED
@@ -36,6 +36,7 @@ end
|
|
36
36
|
require "acts_as_taggable_on/utils"
|
37
37
|
|
38
38
|
require "acts_as_taggable_on/taggable"
|
39
|
+
require "acts_as_taggable_on/acts_as_taggable_on/compatibility"
|
39
40
|
require "acts_as_taggable_on/acts_as_taggable_on/core"
|
40
41
|
require "acts_as_taggable_on/acts_as_taggable_on/collection"
|
41
42
|
require "acts_as_taggable_on/acts_as_taggable_on/cache"
|
@@ -53,6 +54,7 @@ $LOAD_PATH.shift
|
|
53
54
|
|
54
55
|
|
55
56
|
if defined?(ActiveRecord::Base)
|
57
|
+
ActiveRecord::Base.extend ActsAsTaggableOn::Compatibility
|
56
58
|
ActiveRecord::Base.extend ActsAsTaggableOn::Taggable
|
57
59
|
ActiveRecord::Base.send :include, ActsAsTaggableOn::Tagger
|
58
60
|
end
|
@@ -86,12 +86,10 @@ module ActsAsTaggableOn::Taggable
|
|
86
86
|
group_columns = "#{ActsAsTaggableOn::Tagging.table_name}.tag_id"
|
87
87
|
|
88
88
|
# Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
|
89
|
-
|
90
|
-
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(
|
91
|
-
|
92
|
-
|
93
|
-
tag_scope = tag_scope.joins("JOIN (#{tagging_scope.to_sql}) AS #{ActsAsTaggableOn::Tagging.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id")
|
94
|
-
tag_scope
|
89
|
+
ids = select("#{table_name}.#{primary_key}").map(&:id)
|
90
|
+
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(?)", ids).group(group_columns)
|
91
|
+
|
92
|
+
tag_scope.joins("JOIN (#{tagging_scope.to_sql}) AS #{ActsAsTaggableOn::Tagging.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id")
|
95
93
|
end
|
96
94
|
|
97
95
|
##
|
@@ -166,7 +164,7 @@ module ActsAsTaggableOn::Taggable
|
|
166
164
|
scoped_select = "#{table_name}.#{primary_key}"
|
167
165
|
select_query = "#{select(scoped_select).to_sql}"
|
168
166
|
|
169
|
-
res = ActiveRecord::Base.connection.select_all(select_query).map { |item| item.values }.flatten.join(",")
|
167
|
+
res = ActiveRecord::Base.connection.select_all(select_query).map { |item| item.values }.flatten.compact.join(",")
|
170
168
|
res = "NULL" if res.blank?
|
171
169
|
|
172
170
|
tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{res})")
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module ActsAsTaggableOn::Compatibility
|
2
|
+
def has_many_with_compatibility(name, options = {}, &extention)
|
3
|
+
if ActiveRecord::VERSION::MAJOR >= 4
|
4
|
+
scope, opts = build_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_scope_and_options(opts)
|
12
|
+
scope_opts, opts = parse_options(opts)
|
13
|
+
|
14
|
+
unless scope_opts.empty?
|
15
|
+
scope = lambda do
|
16
|
+
scope_opts.inject(self) { |result, hash| result.send *hash }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
[defined?(scope) ? scope : nil, opts]
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse_options(opts)
|
24
|
+
scope_opts = {}
|
25
|
+
[:order, :having, :select, :group, :limit, :offset, :readonly].each do |o|
|
26
|
+
scope_opts[o] = opts.delete o if opts[o]
|
27
|
+
end
|
28
|
+
scope_opts[:where] = opts.delete :conditions if opts[:conditions]
|
29
|
+
scope_opts[:joins] = opts.delete :include if opts [:include]
|
30
|
+
scope_opts[:distinct] = opts.delete :uniq if opts[:uniq]
|
31
|
+
|
32
|
+
[scope_opts, opts]
|
33
|
+
end
|
34
|
+
end
|
@@ -13,28 +13,30 @@ module ActsAsTaggableOn::Taggable
|
|
13
13
|
end
|
14
14
|
|
15
15
|
module ClassMethods
|
16
|
+
|
16
17
|
def initialize_acts_as_taggable_on_core
|
17
18
|
include taggable_mixin
|
18
19
|
tag_types.map(&:to_s).each do |tags_type|
|
19
20
|
tag_type = tags_type.to_s.singularize
|
20
21
|
context_taggings = "#{tag_type}_taggings".to_sym
|
21
22
|
context_tags = tags_type.to_sym
|
22
|
-
taggings_order = (preserve_tag_order? ? "#{ActsAsTaggableOn::Tagging.table_name}.id" :
|
23
|
-
|
23
|
+
taggings_order = (preserve_tag_order? ? "#{ActsAsTaggableOn::Tagging.table_name}.id" : [])
|
24
|
+
|
24
25
|
class_eval do
|
25
26
|
# when preserving tag order, include order option so that for a 'tags' context
|
26
27
|
# the associations tag_taggings & tags are always returned in created order
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
28
|
+
has_many_with_compatibility context_taggings, :as => :taggable,
|
29
|
+
:dependent => :destroy,
|
30
|
+
:class_name => "ActsAsTaggableOn::Tagging",
|
31
|
+
:order => taggings_order,
|
32
|
+
:conditions => ["#{ActsAsTaggableOn::Tagging.table_name}.context = (?)", tags_type],
|
33
|
+
:include => :tag
|
34
|
+
|
35
|
+
has_many_with_compatibility context_tags, :through => context_taggings,
|
36
|
+
:source => :tag,
|
37
|
+
:class_name => "ActsAsTaggableOn::Tag",
|
38
|
+
:order => taggings_order
|
39
|
+
|
38
40
|
end
|
39
41
|
|
40
42
|
taggable_mixin.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
@@ -57,7 +59,7 @@ module ActsAsTaggableOn::Taggable
|
|
57
59
|
super(preserve_tag_order, *tag_types)
|
58
60
|
initialize_acts_as_taggable_on_core
|
59
61
|
end
|
60
|
-
|
62
|
+
|
61
63
|
# all column names are necessary for PostgreSQL group clause
|
62
64
|
def grouped_column_names_for(object)
|
63
65
|
object.column_names.map { |column| "#{object.table_name}.#{column}" }.join(", ")
|
@@ -81,12 +83,14 @@ module ActsAsTaggableOn::Taggable
|
|
81
83
|
# User.tagged_with("awesome", "cool", :owned_by => foo ) # Users that are tagged with just awesome and cool by 'foo'
|
82
84
|
def tagged_with(tags, options = {})
|
83
85
|
tag_list = ActsAsTaggableOn::TagList.from(tags)
|
84
|
-
empty_result =
|
86
|
+
empty_result = where("1 = 0")
|
85
87
|
|
86
88
|
return empty_result if tag_list.empty?
|
87
89
|
|
88
90
|
joins = []
|
89
91
|
conditions = []
|
92
|
+
having = []
|
93
|
+
select_clause = []
|
90
94
|
|
91
95
|
context = options.delete(:on)
|
92
96
|
owned_by = options.delete(:owned_by)
|
@@ -102,15 +106,23 @@ module ActsAsTaggableOn::Taggable
|
|
102
106
|
|
103
107
|
conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"
|
104
108
|
|
109
|
+
if owned_by
|
110
|
+
joins << "JOIN #{ActsAsTaggableOn::Tagging.table_name}" +
|
111
|
+
" ON #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
|
112
|
+
" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)}" +
|
113
|
+
" AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = #{owned_by.id}" +
|
114
|
+
" AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = #{quote_value(owned_by.class.base_class.to_s)}"
|
115
|
+
end
|
116
|
+
|
105
117
|
elsif options.delete(:any)
|
106
118
|
# get tags, drop out if nothing returned (we need at least one)
|
107
|
-
if options.delete(:wild)
|
108
|
-
|
119
|
+
tags = if options.delete(:wild)
|
120
|
+
ActsAsTaggableOn::Tag.named_like_any(tag_list)
|
109
121
|
else
|
110
|
-
|
122
|
+
ActsAsTaggableOn::Tag.named_any(tag_list)
|
111
123
|
end
|
112
124
|
|
113
|
-
return
|
125
|
+
return empty_result unless tags.length > 0
|
114
126
|
|
115
127
|
# setup taggings alias so we can chain, ex: items_locations_taggings_awesome_cool_123
|
116
128
|
# avoid ambiguous column name
|
@@ -129,29 +141,37 @@ module ActsAsTaggableOn::Taggable
|
|
129
141
|
conditions << tags.map { |t| "#{taggings_alias}.tag_id = #{t.id}" }.join(" OR ")
|
130
142
|
select_clause = "DISTINCT #{table_name}.*" unless context and tag_types.one?
|
131
143
|
|
132
|
-
|
144
|
+
if owned_by
|
145
|
+
tagging_join << " AND " +
|
146
|
+
sanitize_sql([
|
147
|
+
"#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?",
|
148
|
+
owned_by.id,
|
149
|
+
owned_by.class.base_class.to_s
|
150
|
+
])
|
151
|
+
end
|
133
152
|
|
153
|
+
joins << tagging_join
|
134
154
|
else
|
135
155
|
tags = ActsAsTaggableOn::Tag.named_any(tag_list)
|
156
|
+
|
136
157
|
return empty_result unless tags.length == tag_list.length
|
137
158
|
|
138
159
|
tags.each do |tag|
|
139
|
-
|
140
160
|
taggings_alias = adjust_taggings_alias("#{alias_base_name[0..11]}_taggings_#{sha_prefix(tag.name)}")
|
141
|
-
|
142
161
|
tagging_join = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
|
143
162
|
" ON #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
|
144
163
|
" AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}" +
|
145
164
|
" AND #{taggings_alias}.tag_id = #{tag.id}"
|
165
|
+
|
146
166
|
tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context
|
147
167
|
|
148
168
|
if owned_by
|
149
169
|
tagging_join << " AND " +
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
170
|
+
sanitize_sql([
|
171
|
+
"#{taggings_alias}.tagger_id = ? AND #{taggings_alias}.tagger_type = ?",
|
172
|
+
owned_by.id,
|
173
|
+
owned_by.class.base_class.to_s
|
174
|
+
])
|
155
175
|
end
|
156
176
|
|
157
177
|
joins << tagging_join
|
@@ -171,13 +191,13 @@ module ActsAsTaggableOn::Taggable
|
|
171
191
|
having = "COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
|
172
192
|
end
|
173
193
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
194
|
+
select(select_clause) \
|
195
|
+
.joins(joins.join(" ")) \
|
196
|
+
.where(conditions.join(" AND ")) \
|
197
|
+
.group(group) \
|
198
|
+
.having(having) \
|
199
|
+
.order(options[:order]) \
|
200
|
+
.readonly(false)
|
181
201
|
end
|
182
202
|
|
183
203
|
def is_taggable?
|
@@ -252,12 +272,10 @@ module ActsAsTaggableOn::Taggable
|
|
252
272
|
|
253
273
|
if ActsAsTaggableOn::Tag.using_postgresql?
|
254
274
|
group_columns = grouped_column_names_for(ActsAsTaggableOn::Tag)
|
255
|
-
scope
|
275
|
+
scope.order("max(#{tagging_table_name}.created_at)").group(group_columns)
|
256
276
|
else
|
257
|
-
scope
|
258
|
-
end
|
259
|
-
|
260
|
-
scope.all
|
277
|
+
scope.group("#{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key}")
|
278
|
+
end.to_a
|
261
279
|
end
|
262
280
|
|
263
281
|
##
|
@@ -267,7 +285,7 @@ module ActsAsTaggableOn::Taggable
|
|
267
285
|
# when preserving tag order, return tags in created order
|
268
286
|
# if we added the order to the association this would always apply
|
269
287
|
scope = scope.order("#{ActsAsTaggableOn::Tagging.table_name}.id") if self.class.preserve_tag_order?
|
270
|
-
scope
|
288
|
+
scope
|
271
289
|
end
|
272
290
|
|
273
291
|
def set_tag_list_on(context, new_list)
|
@@ -309,7 +327,6 @@ module ActsAsTaggableOn::Taggable
|
|
309
327
|
def save_tags
|
310
328
|
tagging_contexts.each do |context|
|
311
329
|
next unless tag_list_cache_set_on(context)
|
312
|
-
|
313
330
|
# List of currently assigned tag names
|
314
331
|
tag_list = tag_list_cache_on(context).uniq
|
315
332
|
|
@@ -321,13 +338,22 @@ module ActsAsTaggableOn::Taggable
|
|
321
338
|
|
322
339
|
# Tag maintenance based on whether preserving the created order of tags
|
323
340
|
if self.class.preserve_tag_order?
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
341
|
+
old_tags, new_tags = current_tags - tags, tags - current_tags
|
342
|
+
|
343
|
+
shared_tags = current_tags & tags
|
344
|
+
|
345
|
+
if shared_tags.any? && tags[0...shared_tags.size] != shared_tags
|
346
|
+
index = shared_tags.each_with_index { |_, i| break i unless shared_tags[i] == tags[i] }
|
347
|
+
|
348
|
+
# Update arrays of tag objects
|
349
|
+
old_tags |= current_tags[index...current_tags.size]
|
350
|
+
new_tags |= current_tags[index...current_tags.size] & shared_tags
|
351
|
+
|
352
|
+
# Order the array of tag objects to match the tag list
|
353
|
+
new_tags = tags.map do |t|
|
354
|
+
new_tags.find { |n| n.name.downcase == t.name.downcase }
|
355
|
+
end.compact
|
356
|
+
end
|
331
357
|
else
|
332
358
|
# Delete discarded tags and create new tags
|
333
359
|
old_tags = current_tags - tags
|
@@ -336,8 +362,7 @@ module ActsAsTaggableOn::Taggable
|
|
336
362
|
|
337
363
|
# Find taggings to remove:
|
338
364
|
if old_tags.present?
|
339
|
-
old_taggings = taggings.where(:tagger_type => nil, :tagger_id => nil,
|
340
|
-
:context => context.to_s, :tag_id => old_tags).all
|
365
|
+
old_taggings = taggings.where(:tagger_type => nil, :tagger_id => nil, :context => context.to_s, :tag_id => old_tags)
|
341
366
|
end
|
342
367
|
|
343
368
|
# Destroy old taggings:
|