acts-as-taggable-on 2.0.0.pre1 → 2.0.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,8 +1,6 @@
1
1
  source :gemcutter
2
2
 
3
- gem 'rails', '3.0.0.beta'
4
-
5
- group :test do
6
- gem 'rspec', '2.0.0.beta.1'
7
- gem 'sqlite3-ruby', :require => 'sqlite3'
8
- end
3
+ # Rails 3.0
4
+ gem 'rails', '3.0.0.beta'
5
+ gem 'rspec', '2.0.0.beta.1'
6
+ gem 'sqlite3-ruby', '1.2.5', :require => 'sqlite3'
@@ -31,6 +31,16 @@ To install the gem, add this to your config/environment.rb:
31
31
 
32
32
  After that, you can run "rake gems:install" to install the gem if you don't already have it.
33
33
 
34
+ == Rails 3.0
35
+
36
+ Acts As Taggable On is now useable in Rails 3.0, thanks to the excellent work of Szymon Nowak
37
+ and Jelle Vandebeeck. Because backwards compatibility is hard to maintain, their work is available
38
+ in the feature/rails3_compatibility branch.
39
+
40
+ A Rails 3.0 compatible version of the gem is also available:
41
+
42
+ gem install acts-as-taggable-on -v=2.0.0.pre1
43
+
34
44
  === Post Installation (Rails)
35
45
 
36
46
  1. script/generate acts_as_taggable_on_migration
data/Rakefile CHANGED
@@ -1,5 +1,45 @@
1
- gem 'rspec', '2.0.0.beta.1'
2
- require 'rspec/core/rake_task'
1
+ begin
2
+ # Rspec 2.0
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc 'Default: run specs'
6
+ task :default => :spec
7
+ Rspec::Core::RakeTask.new do |t|
8
+ t.pattern = "spec/**/*_spec.rb"
9
+ end
10
+
11
+ Rspec::Core::RakeTask.new('rcov') do |t|
12
+ t.pattern = "spec/**/*_spec.rb"
13
+ t.rcov = true
14
+ t.rcov_opts = ['--exclude', 'spec']
15
+ end
16
+
17
+ rescue LoadError
18
+ # Rspec 1.3.0
19
+ require 'spec/rake/spectask'
20
+
21
+ desc 'Default: run specs'
22
+ task :default => :spec
23
+ Spec::Rake::SpecTask.new do |t|
24
+ t.spec_files = FileList["spec/**/*_spec.rb"]
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new('rcov') do |t|
28
+ t.spec_files = FileList["spec/**/*_spec.rb"]
29
+ t.rcov = true
30
+ t.rcov_opts = ['--exclude', 'spec']
31
+ end
32
+ rescue LoadError
33
+ puts "Rspec not available. Install it with: gem install rspec"
34
+ end
35
+
36
+ namespace 'rails2.3' do
37
+ task :spec do
38
+ gemfile = File.join(File.dirname(__FILE__), 'lib', 'acts_as_taggable_on', 'compatibility', 'Gemfile')
39
+ ENV['BUNDLE_GEMFILE'] = gemfile
40
+ Rake::Task['spec'].invoke
41
+ end
42
+ end
3
43
 
4
44
  begin
5
45
  require 'jeweler'
@@ -14,17 +54,5 @@ begin
14
54
  end
15
55
  Jeweler::GemcutterTasks.new
16
56
  rescue LoadError
17
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
18
- end
19
-
20
- desc 'Default: run specs'
21
- task :default => :spec
22
- Rspec::Core::RakeTask.new do |t|
23
- t.pattern = "spec/**/*_spec.rb"
24
- end
25
-
26
- Rspec::Core::RakeTask.new('rcov') do |t|
27
- t.pattern = "spec/**/*_spec.rb"
28
- t.rcov = true
29
- t.rcov_opts = ['--exclude', 'spec']
30
- end
57
+ puts "Jeweler not available. Install it with: gem install jeweler"
58
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.0.pre1
1
+ 2.0.0.pre3
@@ -1,27 +1,30 @@
1
- begin
2
- # Try to require the preresolved locked set of gems.
3
- require File.expand_path("../.bundle/environment", __FILE__)
4
- rescue LoadError
5
- # Fall back on doing an unlocked resolve at runtime.
6
- require "rubygems"
7
- require "bundler"
8
- Bundler.setup
9
- end
10
-
11
- Bundler.require
12
-
13
1
  require "active_record"
14
2
  require "action_view"
15
3
 
16
- require "acts_as_taggable_on/group_helper"
4
+ if ActiveRecord::VERSION::MAJOR < 3
5
+ require "acts_as_taggable_on/compatibility/active_record_backports"
6
+ require "acts_as_taggable_on/compatibility/tag"
7
+ require "acts_as_taggable_on/compatibility/tagging"
8
+ end
9
+
17
10
  require "acts_as_taggable_on/acts_as_taggable_on"
11
+ require "acts_as_taggable_on/acts_as_taggable_on/core"
12
+ require "acts_as_taggable_on/acts_as_taggable_on/aggregate"
13
+ require "acts_as_taggable_on/acts_as_taggable_on/cache"
14
+ require "acts_as_taggable_on/acts_as_taggable_on/ownership"
15
+ require "acts_as_taggable_on/acts_as_taggable_on/related"
16
+
18
17
  require "acts_as_taggable_on/acts_as_tagger"
19
18
  require "acts_as_taggable_on/tag"
20
19
  require "acts_as_taggable_on/tag_list"
21
20
  require "acts_as_taggable_on/tags_helper"
22
21
  require "acts_as_taggable_on/tagging"
23
22
 
24
- ActiveRecord::Base.send :include, ActiveRecord::Acts::TaggableOn
25
- ActiveRecord::Base.send :include, ActiveRecord::Acts::Tagger
23
+ if defined?(ActiveRecord::Base)
24
+ ActiveRecord::Base.extend ActsAsTaggableOn::Taggable
25
+ ActiveRecord::Base.send :include, ActsAsTaggableOn::Tagger
26
+ end
26
27
 
27
- ActionView::Base.send :include, TagsHelper
28
+ if defined?(ActionView::Base)
29
+ ActionView::Base.send :include, TagsHelper
30
+ end
@@ -1,426 +1,41 @@
1
- module ActiveRecord
2
- module Acts
3
- module TaggableOn
4
-
5
- def self.included(base)
6
- base.extend(ClassMethods)
7
- end
8
-
9
- module ClassMethods
10
-
11
- def taggable?
12
- false
13
- end
14
-
15
- def acts_as_taggable
16
- acts_as_taggable_on :tags
17
- end
18
-
19
- def acts_as_taggable_on(*args)
20
- args.flatten! if args
21
- args.compact! if args
22
-
23
- for tag_type in args
24
- tag_type = tag_type.to_s
25
- # use aliased_join_table_name for context condition so that sphinx can join multiple
26
- # tag references from same model without getting an ambiguous column error
27
- class_eval do
28
- has_many "#{tag_type.singularize}_taggings".to_sym, :as => :taggable, :dependent => :destroy,
29
- :include => :tag, :conditions => ['#{aliased_join_table_name || Tagging.table_name rescue Tagging.table_name}.context = ?',tag_type], :class_name => "Tagging"
30
- has_many "#{tag_type}".to_sym, :through => "#{tag_type.singularize}_taggings".to_sym, :source => :tag
31
- end
32
-
33
- class_eval <<-RUBY
34
-
35
- def self.taggable?
36
- true
37
- end
38
-
39
- def self.caching_#{tag_type.singularize}_list?
40
- caching_tag_list_on?("#{tag_type}")
41
- end
42
-
43
- def self.#{tag_type.singularize}_counts(options={})
44
- tag_counts_on('#{tag_type}',options)
45
- end
46
-
47
- def #{tag_type.singularize}_list
48
- tag_list_on('#{tag_type}')
49
- end
50
-
51
- def #{tag_type.singularize}_list=(new_tags)
52
- set_tag_list_on('#{tag_type}',new_tags)
53
- end
54
-
55
- def #{tag_type.singularize}_counts(options = {})
56
- tag_counts_on('#{tag_type}',options)
57
- end
58
-
59
- def #{tag_type}_from(owner)
60
- tag_list_on('#{tag_type}', owner)
61
- end
62
-
63
- def find_related_#{tag_type}(options = {})
64
- related_tags_for('#{tag_type}', self.class, options)
65
- end
66
- alias_method :find_related_on_#{tag_type}, :find_related_#{tag_type}
67
-
68
- def find_related_#{tag_type}_for(klass, options = {})
69
- related_tags_for('#{tag_type}', klass, options)
70
- end
71
-
72
- def find_matching_contexts(search_context, result_context, options = {})
73
- matching_contexts_for(search_context.to_s, result_context.to_s, self.class, options)
74
- end
75
-
76
- def find_matching_contexts_for(klass, search_context, result_context, options = {})
77
- matching_contexts_for(search_context.to_s, result_context.to_s, klass, options)
78
- end
79
-
80
- def top_#{tag_type}(limit = 10)
81
- tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)
82
- end
83
-
84
- def self.top_#{tag_type}(limit = 10)
85
- tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)
86
- end
87
-
88
- RUBY
89
- end
90
-
91
- if respond_to?(:tag_types)
92
- write_inheritable_attribute( :tag_types, (tag_types + args).uniq )
93
- else
94
- class_eval do
95
- write_inheritable_attribute(:tag_types, args.uniq)
96
- class_inheritable_reader :tag_types
97
-
98
- has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag
99
- has_many :base_tags, :class_name => "Tag", :through => :taggings, :source => :tag
100
-
101
- attr_writer :custom_contexts
102
-
103
- before_save :save_cached_tag_list
104
-
105
- after_save:save_tags
106
-
107
- scope :tagged_with, lambda{ |*args|
108
- find_options_for_find_tagged_with(*args)
109
- }
110
- end
111
-
112
- include ActiveRecord::Acts::TaggableOn::InstanceMethods
113
- extend ActiveRecord::Acts::TaggableOn::SingletonMethods
114
- alias_method_chain :reload, :tag_list
115
- end
116
- end
117
-
118
- end
119
-
120
- module SingletonMethods
121
-
122
- include ActiveRecord::Acts::TaggableOn::GroupHelper
123
-
124
- # Pass either a tag string, or an array of strings or tags
125
- #
126
- # Options:
127
- # :any - find models that match any of the given tags
128
- # :exclude - Find models that are not tagged with the given tags
129
- # :match_all - Find models that match all of the given tags, not just one
130
- # :conditions - A piece of SQL conditions to add to the query
131
- # :on - scopes the find to a context
132
- # def find_tagged_with(*args)
133
- # find_options_for_find_tagged_with(*args)
134
- # end
135
-
136
- def caching_tag_list_on?(context)
137
- column_names.include?("cached_#{context.to_s.singularize}_list")
138
- end
139
-
140
- def tag_counts_on(context, options = {})
141
- find_for_tag_counts(options.merge({:on => context.to_s}))
142
- end
143
-
144
- def all_tag_counts(options = {})
145
- find_for_tag_counts(options)
146
- end
147
-
148
- def find_options_for_find_tagged_with(tags, options = {})
149
- tag_list = TagList.from(tags)
150
-
151
- return {} if tag_list.empty?
152
-
153
- joins = []
154
- conditions = []
155
-
156
- context = options.delete(:on)
157
-
158
- if options.delete(:exclude)
159
- tags_conditions = tag_list.map { |t| sanitize_sql(["#{Tag.table_name}.name LIKE ?", t]) }.join(" OR ")
160
- conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{Tagging.table_name}.taggable_id FROM #{Tagging.table_name} JOIN #{Tag.table_name} ON #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND (#{tags_conditions}) WHERE #{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"
161
-
162
- elsif options.delete(:any)
163
- tags_conditions = tag_list.map { |t| sanitize_sql(["#{Tag.table_name}.name LIKE ?", t]) }.join(" OR ")
164
- conditions << "#{table_name}.#{primary_key} IN (SELECT #{Tagging.table_name}.taggable_id FROM #{Tagging.table_name} JOIN #{Tag.table_name} ON #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND (#{tags_conditions}) WHERE #{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"
165
-
166
- else
167
- tags = Tag.named_any(tag_list)
168
- return { :conditions => "1 = 0" } unless tags.length == tag_list.length
169
-
170
- tags.each do |tag|
171
- safe_tag = tag.name.gsub(/[^a-zA-Z0-9]/, '')
172
- prefix = "#{safe_tag}_#{rand(1024)}"
173
-
174
- taggings_alias = "#{table_name}_taggings_#{prefix}"
175
-
176
- tagging_join = "JOIN #{Tagging.table_name} #{taggings_alias}" +
177
- " ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
178
- " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}" +
179
- " AND #{taggings_alias}.tag_id = #{tag.id}"
180
- tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context
181
-
182
- joins << tagging_join
183
- end
184
- end
185
-
186
- taggings_alias, tags_alias = "#{table_name}_taggings_group", "#{table_name}_tags_group"
187
-
188
- if options.delete(:match_all)
189
- joins << "LEFT OUTER JOIN #{Tagging.table_name} #{taggings_alias}" +
190
- " ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
191
- " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"
192
-
193
- group = "#{grouped_column_names_for(self)} HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
194
- end
195
-
196
- Tag.joins(joins.join(" ")).group(group).where(conditions.join(" AND ")).readonly(false)
197
-
198
- # { :joins => joins.join(" "),
199
- # :group => group,
200
- # :conditions => conditions.join(" AND "),
201
- # :readonly => false }.update(options)
202
- end
203
-
204
- # Calculate the tag counts for all tags.
205
- #
206
- # Options:
207
- # :start_at - Restrict the tags to those created after a certain time
208
- # :end_at - Restrict the tags to those created before a certain time
209
- # :conditions - A piece of SQL conditions to add to the query
210
- # :limit - The maximum number of tags to return
211
- # :order - A piece of SQL to order by. Eg 'tags.count desc' or 'taggings.created_at desc'
212
- # :at_least - Exclude tags with a frequency less than the given value
213
- # :at_most - Exclude tags with a frequency greater than the given value
214
- # :on - Scope the find to only include a certain context
215
- def find_for_tag_counts(options = {})
216
- options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :on, :id
217
-
218
- start_at = sanitize_sql(["#{Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
219
- end_at = sanitize_sql(["#{Tagging.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
220
-
221
- taggable_type = sanitize_sql(["#{Tagging.table_name}.taggable_type = ?", base_class.name])
222
- taggable_id = sanitize_sql(["#{Tagging.table_name}.taggable_id = ?", options.delete(:id)]) if options[:id]
223
- options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]
224
-
225
- conditions = [
226
- taggable_type,
227
- taggable_id,
228
- options[:conditions],
229
- start_at,
230
- end_at
231
- ]
232
-
233
- conditions = conditions.compact.join(' AND ')
234
-
235
- joins = ["LEFT OUTER JOIN #{Tagging.table_name} ON #{Tag.table_name}.id = #{Tagging.table_name}.tag_id"]
236
- joins << sanitize_sql(["AND #{Tagging.table_name}.context = ?",options.delete(:on).to_s]) unless options[:on].nil?
237
- joins << " INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{Tagging.table_name}.taggable_id"
238
-
239
- unless descends_from_active_record?
240
- # Current model is STI descendant, so add type checking to the join condition
241
- joins << " AND #{table_name}.#{inheritance_column} = '#{name}'"
242
- end
243
-
244
- at_least = sanitize_sql(['COUNT(*) >= ?', options.delete(:at_least)]) if options[:at_least]
245
- at_most = sanitize_sql(['COUNT(*) <= ?', options.delete(:at_most)]) if options[:at_most]
246
- having = [at_least, at_most].compact.join(' AND ')
247
- group_by = "#{grouped_column_names_for(Tag)} HAVING COUNT(*) > 0"
248
- group_by << " AND #{having}" unless having.blank?
249
-
250
- Tag.select("#{Tag.table_name}.*, COUNT(*) AS count").joins(joins.join(" ")).where(conditions).group(group_by).limit(options[:limit]).order(options[:order])
251
-
252
- end
253
-
254
- def is_taggable?
255
- true
256
- end
257
-
258
- end
259
-
260
- module InstanceMethods
261
-
262
- include ActiveRecord::Acts::TaggableOn::GroupHelper
263
-
264
- def custom_contexts
265
- @custom_contexts ||= []
266
- end
267
-
268
- def is_taggable?
269
- self.class.is_taggable?
270
- end
271
-
272
- def add_custom_context(value)
273
- custom_contexts << value.to_s unless custom_contexts.include?(value.to_s) or self.class.tag_types.map(&:to_s).include?(value.to_s)
274
- end
275
-
276
- def tag_list_on(context, owner = nil)
277
- add_custom_context(context)
278
- cache = tag_list_cache_on(context)
279
- return owner ? cache[owner] : cache[owner] if cache[owner]
280
-
281
- if !owner && self.class.caching_tag_list_on?(context) and !(cached_value = cached_tag_list_on(context)).nil?
282
- cache[owner] = TagList.from(cached_tag_list_on(context))
283
- else
284
- cache[owner] = TagList.new(*tags_on(context, owner).map(&:name))
285
- end
286
- end
287
-
288
- def all_tags_list_on(context)
289
- variable_name = "@all_#{context.to_s.singularize}_list"
290
- return instance_variable_get(variable_name) if instance_variable_get(variable_name)
291
- instance_variable_set(variable_name, TagList.new(all_tags_on(context).map(&:name)).freeze)
292
- end
293
-
294
- def all_tags_on(context)
295
- opts = ["#{Tagging.table_name}.context = ?", context.to_s]
296
- base_tags.where(opts).order("#{Tagging.table_name}.created_at")
297
- end
298
-
299
- def tags_on(context, owner = nil)
300
- if owner
301
- opts = ["#{Tagging.table_name}.context = ? AND #{Tagging.table_name}.tagger_id = ? AND #{Tagging.table_name}.tagger_type = ?", context.to_s, owner.id, owner.class.to_s]
302
- else
303
- opts = ["#{Tagging.table_name}.context = ? AND #{Tagging.table_name}.tagger_id IS NULL", context.to_s]
304
- end
305
- base_tags.where(opts)
306
- end
307
-
308
- def cached_tag_list_on(context)
309
- self["cached_#{context.to_s.singularize}_list"]
310
- end
311
-
312
- def tag_list_cache_on(context)
313
- variable_name = "@#{context.to_s.singularize}_list"
314
- cache = instance_variable_get(variable_name)
315
- instance_variable_set(variable_name, cache = {}) unless cache
316
- cache
317
- end
318
-
319
- def set_tag_list_on(context, new_list, tagger = nil)
320
- tag_list_cache_on(context)[tagger] = TagList.from(new_list)
321
- add_custom_context(context)
322
- end
323
-
324
- def tag_counts_on(context, options={})
325
- self.class.tag_counts_on(context, options.merge(:id => id))
326
- end
327
-
328
- def related_tags_for(context, klass, options = {})
329
- search_conditions = related_search_options(context, klass, options)
330
-
331
- klass.select(search_conditions[:select]).from(search_conditions[:from]).where(search_conditions[:conditions]).group(search_conditions[:group]).order(search_conditions[:order])
332
- end
333
-
334
- def related_search_options(context, klass, options = {})
335
- tags_to_find = tags_on(context).collect { |t| t.name }
336
-
337
- exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass
338
-
339
- { :select => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count",
340
- :from => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
341
- :conditions => ["#{exclude_self} #{klass.table_name}.id = #{Tagging.table_name}.taggable_id AND #{Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND #{Tag.table_name}.name IN (?)", tags_to_find],
342
- :group => grouped_column_names_for(klass),
343
- :order => "count DESC"
344
- }.update(options)
345
- end
346
-
347
- def matching_contexts_for(search_context, result_context, klass, options = {})
348
- search_conditions = matching_context_search_options(search_context, result_context, klass, options)
349
-
350
- klass.select(search_conditions[:select]).from(search_conditions[:from]).where(search_conditions[:conditions]).group(search_conditions[:group]).order(search_conditions[:order])
351
- end
352
-
353
- def matching_context_search_options(search_context, result_context, klass, options = {})
354
- tags_to_find = tags_on(search_context).collect { |t| t.name }
355
-
356
- exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass
357
-
358
- { :select => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count",
359
- :from => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
360
- :conditions => ["#{exclude_self} #{klass.table_name}.id = #{Tagging.table_name}.taggable_id AND #{Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND #{Tag.table_name}.name IN (?) AND #{Tagging.table_name}.context = ?", tags_to_find, result_context],
361
- :group => grouped_column_names_for(klass),
362
- :order => "count DESC"
363
- }.update(options)
364
- end
365
-
366
- def save_cached_tag_list
367
- self.class.tag_types.map(&:to_s).each do |tag_type|
368
- if self.class.send("caching_#{tag_type.singularize}_list?")
369
- self["cached_#{tag_type.singularize}_list"] = tag_list_cache_on(tag_type.singularize).to_a.flatten.compact.join(', ')
370
- end
371
- end
372
- end
373
-
374
- def save_tags
375
- contexts = custom_contexts + self.class.tag_types.map(&:to_s)
376
-
377
- transaction do
378
- contexts.each do |context|
379
- cache = tag_list_cache_on(context)
380
-
381
- cache.each do |owner, list|
382
- new_tags = Tag.find_or_create_all_with_like_by_name(list.uniq)
383
- taggings = Tagging.where({ :taggable_id => self.id, :taggable_type => self.class.base_class.to_s })
384
-
385
- # Destroy old taggings:
386
- if owner
387
- old_tags = tags_on(context, owner) - new_tags
388
- old_taggings = Tagging.where({ :taggable_id => self.id, :taggable_type => self.class.base_class.to_s, :tag_id => old_tags, :tagger_id => owner.id, :tagger_type => owner.class.to_s, :context => context })
389
-
390
- Tagging.destroy_all :id => old_taggings.map(&:id)
391
- else
392
- old_tags = tags_on(context) - new_tags
393
- base_tags.delete(*old_tags)
394
- end
1
+ module ActsAsTaggableOn
2
+ module Taggable
3
+ def taggable?
4
+ false
5
+ end
395
6
 
396
- new_tags.reject! { |tag| taggings.any? { |tagging|
397
- tagging.tag_id == tag.id &&
398
- tagging.tagger_id == (owner ? owner.id : nil) &&
399
- tagging.tagger_type == (owner ? owner.class.to_s : nil) &&
400
- tagging.context == context
401
- }
402
- }
7
+ def acts_as_taggable
8
+ acts_as_taggable_on :tags
9
+ end
403
10
 
404
- # create new taggings:
405
- new_tags.each do |tag|
406
- Tagging.create!(:tag_id => tag.id, :context => context, :tagger => owner, :taggable => self)
407
- end
408
- end
409
- end
410
- end
11
+ def acts_as_taggable_on(*tag_types)
12
+ tag_types = tag_types.to_a.flatten.compact.map(&:to_sym)
411
13
 
412
- true
14
+ if taggable?
15
+ write_inheritable_attribute(:tag_types, (self.tag_types + tag_types).uniq)
16
+ else
17
+ if ::ActiveRecord::VERSION::MAJOR < 3
18
+ include ActsAsTaggableOn::ActiveRecord::Backports
413
19
  end
20
+
21
+ write_inheritable_attribute(:tag_types, tag_types)
22
+ class_inheritable_reader(:tag_types)
23
+
24
+ class_eval do
25
+ has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag
26
+ has_many :base_tags, :class_name => "Tag", :through => :taggings, :source => :tag
414
27
 
415
- def reload_with_tag_list(*args)
416
- self.class.tag_types.each do |tag_type|
417
- instance_variable_set("@#{tag_type.to_s.singularize}_list", nil)
28
+ def self.taggable?
29
+ true
418
30
  end
419
-
420
- reload_without_tag_list(*args)
421
31
  end
422
-
423
32
  end
33
+
34
+ include Core
35
+ include Aggregate
36
+ include Cache
37
+ include Ownership
38
+ include Related
424
39
  end
425
40
  end
426
41
  end