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

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.
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ == 2010-02-17
2
+ * Converted the plugin to be compatible with Rails3
3
+
1
4
  == 2009-12-02
2
5
 
3
6
  * PostgreSQL is now supported (via morgoth)
@@ -12,10 +15,10 @@
12
15
  * Removed extraneous down migration cruft (azabaj)
13
16
 
14
17
  == 2008-06-09
15
-
18
+
16
19
  * Added support for Single Table Inheritance
17
20
  * Adding gemspec and rails/init.rb for gemified plugin
18
-
21
+
19
22
  == 2007-12-12
20
23
 
21
24
  * Added ability to use dynamic tag contexts
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :gemcutter
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
@@ -31,16 +31,6 @@ 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
-
44
34
  === Post Installation (Rails)
45
35
 
46
36
  1. script/generate acts_as_taggable_on_migration
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
- require 'spec/rake/spectask'
1
+ gem 'rspec', '2.0.0.beta.1'
2
+ require 'rspec/core/rake_task'
2
3
 
3
4
  begin
4
5
  require 'jeweler'
@@ -18,12 +19,12 @@ end
18
19
 
19
20
  desc 'Default: run specs'
20
21
  task :default => :spec
21
- Spec::Rake::SpecTask.new do |t|
22
- t.spec_files = FileList["spec/**/*_spec.rb"]
22
+ Rspec::Core::RakeTask.new do |t|
23
+ t.pattern = "spec/**/*_spec.rb"
23
24
  end
24
25
 
25
- Spec::Rake::SpecTask.new('rcov') do |t|
26
- t.spec_files = FileList["spec/**/*_spec.rb"]
26
+ Rspec::Core::RakeTask.new('rcov') do |t|
27
+ t.pattern = "spec/**/*_spec.rb"
27
28
  t.rcov = true
28
29
  t.rcov_opts = ['--exclude', 'spec']
29
30
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.9
1
+ 2.0.0.pre1
@@ -1,7 +1,27 @@
1
- require 'acts_as_taggable_on/group_helper'
2
- require 'acts_as_taggable_on/acts_as_taggable_on'
3
- require 'acts_as_taggable_on/acts_as_tagger'
4
- require 'acts_as_taggable_on/tag'
5
- require 'acts_as_taggable_on/tag_list'
6
- require 'acts_as_taggable_on/tags_helper'
7
- require 'acts_as_taggable_on/tagging'
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
+ require "active_record"
14
+ require "action_view"
15
+
16
+ require "acts_as_taggable_on/group_helper"
17
+ require "acts_as_taggable_on/acts_as_taggable_on"
18
+ require "acts_as_taggable_on/acts_as_tagger"
19
+ require "acts_as_taggable_on/tag"
20
+ require "acts_as_taggable_on/tag_list"
21
+ require "acts_as_taggable_on/tags_helper"
22
+ require "acts_as_taggable_on/tagging"
23
+
24
+ ActiveRecord::Base.send :include, ActiveRecord::Acts::TaggableOn
25
+ ActiveRecord::Base.send :include, ActiveRecord::Acts::Tagger
26
+
27
+ ActionView::Base.send :include, TagsHelper
@@ -1,11 +1,13 @@
1
1
  module ActiveRecord
2
2
  module Acts
3
3
  module TaggableOn
4
+
4
5
  def self.included(base)
5
6
  base.extend(ClassMethods)
6
7
  end
7
8
 
8
9
  module ClassMethods
10
+
9
11
  def taggable?
10
12
  false
11
13
  end
@@ -17,6 +19,7 @@ module ActiveRecord
17
19
  def acts_as_taggable_on(*args)
18
20
  args.flatten! if args
19
21
  args.compact! if args
22
+
20
23
  for tag_type in args
21
24
  tag_type = tag_type.to_s
22
25
  # use aliased_join_table_name for context condition so that sphinx can join multiple
@@ -28,6 +31,7 @@ module ActiveRecord
28
31
  end
29
32
 
30
33
  class_eval <<-RUBY
34
+
31
35
  def self.taggable?
32
36
  true
33
37
  end
@@ -43,10 +47,6 @@ module ActiveRecord
43
47
  def #{tag_type.singularize}_list
44
48
  tag_list_on('#{tag_type}')
45
49
  end
46
-
47
- def all_#{tag_type}_list
48
- all_tags_list_on('#{tag_type}')
49
- end
50
50
 
51
51
  def #{tag_type.singularize}_list=(new_tags)
52
52
  set_tag_list_on('#{tag_type}',new_tags)
@@ -72,7 +72,7 @@ module ActiveRecord
72
72
  def find_matching_contexts(search_context, result_context, options = {})
73
73
  matching_contexts_for(search_context.to_s, result_context.to_s, self.class, options)
74
74
  end
75
-
75
+
76
76
  def find_matching_contexts_for(klass, search_context, result_context, options = {})
77
77
  matching_contexts_for(search_context.to_s, result_context.to_s, klass, options)
78
78
  end
@@ -84,8 +84,10 @@ module ActiveRecord
84
84
  def self.top_#{tag_type}(limit = 10)
85
85
  tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)
86
86
  end
87
+
87
88
  RUBY
88
89
  end
90
+
89
91
  if respond_to?(:tag_types)
90
92
  write_inheritable_attribute( :tag_types, (tag_types + args).uniq )
91
93
  else
@@ -99,23 +101,26 @@ module ActiveRecord
99
101
  attr_writer :custom_contexts
100
102
 
101
103
  before_save :save_cached_tag_list
102
- after_save :save_tags
103
104
 
104
- if respond_to?(:named_scope)
105
- named_scope :tagged_with, lambda{ |*args|
106
- find_options_for_find_tagged_with(*args)
107
- }
108
- end
105
+ after_save:save_tags
106
+
107
+ scope :tagged_with, lambda{ |*args|
108
+ find_options_for_find_tagged_with(*args)
109
+ }
109
110
  end
110
111
 
111
112
  include ActiveRecord::Acts::TaggableOn::InstanceMethods
112
113
  extend ActiveRecord::Acts::TaggableOn::SingletonMethods
114
+ alias_method_chain :reload, :tag_list
113
115
  end
114
116
  end
117
+
115
118
  end
116
119
 
117
120
  module SingletonMethods
121
+
118
122
  include ActiveRecord::Acts::TaggableOn::GroupHelper
123
+
119
124
  # Pass either a tag string, or an array of strings or tags
120
125
  #
121
126
  # Options:
@@ -124,21 +129,20 @@ module ActiveRecord
124
129
  # :match_all - Find models that match all of the given tags, not just one
125
130
  # :conditions - A piece of SQL conditions to add to the query
126
131
  # :on - scopes the find to a context
127
- def find_tagged_with(*args)
128
- options = find_options_for_find_tagged_with(*args)
129
- options.blank? ? [] : find(:all,options)
130
- end
132
+ # def find_tagged_with(*args)
133
+ # find_options_for_find_tagged_with(*args)
134
+ # end
131
135
 
132
136
  def caching_tag_list_on?(context)
133
137
  column_names.include?("cached_#{context.to_s.singularize}_list")
134
138
  end
135
139
 
136
140
  def tag_counts_on(context, options = {})
137
- Tag.find(:all, find_options_for_tag_counts(options.merge({:on => context.to_s})))
141
+ find_for_tag_counts(options.merge({:on => context.to_s}))
138
142
  end
139
143
 
140
144
  def all_tag_counts(options = {})
141
- Tag.find(:all, find_options_for_tag_counts(options))
145
+ find_for_tag_counts(options)
142
146
  end
143
147
 
144
148
  def find_options_for_find_tagged_with(tags, options = {})
@@ -151,7 +155,6 @@ module ActiveRecord
151
155
 
152
156
  context = options.delete(:on)
153
157
 
154
-
155
158
  if options.delete(:exclude)
156
159
  tags_conditions = tag_list.map { |t| sanitize_sql(["#{Tag.table_name}.name LIKE ?", t]) }.join(" OR ")
157
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)})"
@@ -163,7 +166,7 @@ module ActiveRecord
163
166
  else
164
167
  tags = Tag.named_any(tag_list)
165
168
  return { :conditions => "1 = 0" } unless tags.length == tag_list.length
166
-
169
+
167
170
  tags.each do |tag|
168
171
  safe_tag = tag.name.gsub(/[^a-zA-Z0-9]/, '')
169
172
  prefix = "#{safe_tag}_#{rand(1024)}"
@@ -190,10 +193,12 @@ module ActiveRecord
190
193
  group = "#{grouped_column_names_for(self)} HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
191
194
  end
192
195
 
193
- { :joins => joins.join(" "),
194
- :group => group,
195
- :conditions => conditions.join(" AND "),
196
- :readonly => false }.update(options)
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)
197
202
  end
198
203
 
199
204
  # Calculate the tag counts for all tags.
@@ -207,10 +212,9 @@ module ActiveRecord
207
212
  # :at_least - Exclude tags with a frequency less than the given value
208
213
  # :at_most - Exclude tags with a frequency greater than the given value
209
214
  # :on - Scope the find to only include a certain context
210
- def find_options_for_tag_counts(options = {})
215
+ def find_for_tag_counts(options = {})
211
216
  options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :on, :id
212
217
 
213
- scope = scope(:find)
214
218
  start_at = sanitize_sql(["#{Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
215
219
  end_at = sanitize_sql(["#{Tagging.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
216
220
 
@@ -227,58 +231,34 @@ module ActiveRecord
227
231
  ]
228
232
 
229
233
  conditions = conditions.compact.join(' AND ')
230
- conditions = merge_conditions(conditions, scope[:conditions]) if scope
231
234
 
232
235
  joins = ["LEFT OUTER JOIN #{Tagging.table_name} ON #{Tag.table_name}.id = #{Tagging.table_name}.tag_id"]
233
236
  joins << sanitize_sql(["AND #{Tagging.table_name}.context = ?",options.delete(:on).to_s]) unless options[:on].nil?
234
237
  joins << " INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{Tagging.table_name}.taggable_id"
235
-
238
+
236
239
  unless descends_from_active_record?
237
240
  # Current model is STI descendant, so add type checking to the join condition
238
241
  joins << " AND #{table_name}.#{inheritance_column} = '#{name}'"
239
242
  end
240
243
 
241
- # Based on a proposed patch by donV to ActiveRecord Base
242
- # This is needed because merge_joins and construct_join are private in ActiveRecord Base
243
- if scope && scope[:joins]
244
- case scope[:joins]
245
- when Array
246
- scope_joins = scope[:joins].flatten
247
- strings = scope_joins.select{|j| j.is_a? String}
248
- joins << strings.join(' ') + " "
249
- symbols = scope_joins - strings
250
- join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, symbols, nil)
251
- joins << " #{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join} "
252
- joins.flatten!
253
- when Symbol, Hash
254
- join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, scope[:joins], nil)
255
- joins << " #{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join} "
256
- when String
257
- joins << scope[:joins]
258
- end
259
- end
260
-
261
244
  at_least = sanitize_sql(['COUNT(*) >= ?', options.delete(:at_least)]) if options[:at_least]
262
245
  at_most = sanitize_sql(['COUNT(*) <= ?', options.delete(:at_most)]) if options[:at_most]
263
246
  having = [at_least, at_most].compact.join(' AND ')
264
247
  group_by = "#{grouped_column_names_for(Tag)} HAVING COUNT(*) > 0"
265
248
  group_by << " AND #{having}" unless having.blank?
266
249
 
267
- { :select => "#{Tag.table_name}.*, COUNT(*) AS count",
268
- :joins => joins.join(" "),
269
- :conditions => conditions,
270
- :group => group_by,
271
- :limit => options[:limit],
272
- :order => options[:order]
273
- }
250
+ Tag.select("#{Tag.table_name}.*, COUNT(*) AS count").joins(joins.join(" ")).where(conditions).group(group_by).limit(options[:limit]).order(options[:order])
251
+
274
252
  end
275
253
 
276
254
  def is_taggable?
277
255
  true
278
256
  end
257
+
279
258
  end
280
259
 
281
260
  module InstanceMethods
261
+
282
262
  include ActiveRecord::Acts::TaggableOn::GroupHelper
283
263
 
284
264
  def custom_contexts
@@ -288,7 +268,7 @@ module ActiveRecord
288
268
  def is_taggable?
289
269
  self.class.is_taggable?
290
270
  end
291
-
271
+
292
272
  def add_custom_context(value)
293
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)
294
274
  end
@@ -297,40 +277,38 @@ module ActiveRecord
297
277
  add_custom_context(context)
298
278
  cache = tag_list_cache_on(context)
299
279
  return owner ? cache[owner] : cache[owner] if cache[owner]
300
-
280
+
301
281
  if !owner && self.class.caching_tag_list_on?(context) and !(cached_value = cached_tag_list_on(context)).nil?
302
282
  cache[owner] = TagList.from(cached_tag_list_on(context))
303
283
  else
304
284
  cache[owner] = TagList.new(*tags_on(context, owner).map(&:name))
305
285
  end
306
286
  end
307
-
287
+
308
288
  def all_tags_list_on(context)
309
289
  variable_name = "@all_#{context.to_s.singularize}_list"
310
290
  return instance_variable_get(variable_name) if instance_variable_get(variable_name)
311
291
  instance_variable_set(variable_name, TagList.new(all_tags_on(context).map(&:name)).freeze)
312
292
  end
313
-
293
+
314
294
  def all_tags_on(context)
315
- opts = {:conditions => ["#{Tagging.table_name}.context = ?", context.to_s]}
316
- base_tags.find(:all, opts.merge(:order => "#{Tagging.table_name}.created_at"))
295
+ opts = ["#{Tagging.table_name}.context = ?", context.to_s]
296
+ base_tags.where(opts).order("#{Tagging.table_name}.created_at")
317
297
  end
318
298
 
319
299
  def tags_on(context, owner = nil)
320
300
  if owner
321
- opts = {:conditions => ["#{Tagging.table_name}.context = ? AND #{Tagging.table_name}.tagger_id = ? AND #{Tagging.table_name}.tagger_type = ?",
322
- context.to_s, owner.id, owner.class.to_s]}
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]
323
302
  else
324
- opts = {:conditions => ["#{Tagging.table_name}.context = ? AND #{Tagging.table_name}.tagger_id IS NULL", context.to_s]}
303
+ opts = ["#{Tagging.table_name}.context = ? AND #{Tagging.table_name}.tagger_id IS NULL", context.to_s]
325
304
  end
326
-
327
- base_tags.find(:all, opts)
305
+ base_tags.where(opts)
328
306
  end
329
307
 
330
308
  def cached_tag_list_on(context)
331
309
  self["cached_#{context.to_s.singularize}_list"]
332
310
  end
333
-
311
+
334
312
  def tag_list_cache_on(context)
335
313
  variable_name = "@#{context.to_s.singularize}_list"
336
314
  cache = instance_variable_get(variable_name)
@@ -350,7 +328,7 @@ module ActiveRecord
350
328
  def related_tags_for(context, klass, options = {})
351
329
  search_conditions = related_search_options(context, klass, options)
352
330
 
353
- klass.find(:all, search_conditions)
331
+ klass.select(search_conditions[:select]).from(search_conditions[:from]).where(search_conditions[:conditions]).group(search_conditions[:group]).order(search_conditions[:order])
354
332
  end
355
333
 
356
334
  def related_search_options(context, klass, options = {})
@@ -365,13 +343,13 @@ module ActiveRecord
365
343
  :order => "count DESC"
366
344
  }.update(options)
367
345
  end
368
-
346
+
369
347
  def matching_contexts_for(search_context, result_context, klass, options = {})
370
348
  search_conditions = matching_context_search_options(search_context, result_context, klass, options)
371
349
 
372
- klass.find(:all, search_conditions)
350
+ klass.select(search_conditions[:select]).from(search_conditions[:from]).where(search_conditions[:conditions]).group(search_conditions[:group]).order(search_conditions[:order])
373
351
  end
374
-
352
+
375
353
  def matching_context_search_options(search_context, result_context, klass, options = {})
376
354
  tags_to_find = tags_on(search_context).collect { |t| t.name }
377
355
 
@@ -388,7 +366,7 @@ module ActiveRecord
388
366
  def save_cached_tag_list
389
367
  self.class.tag_types.map(&:to_s).each do |tag_type|
390
368
  if self.class.send("caching_#{tag_type.singularize}_list?")
391
- send(:"cached_#{tag_type.singularize}_list=", tag_list_cache_on(tag_type.singularize).to_a.flatten.compact.join(', '))
369
+ self["cached_#{tag_type.singularize}_list"] = tag_list_cache_on(tag_type.singularize).to_a.flatten.compact.join(', ')
392
370
  end
393
371
  end
394
372
  end
@@ -399,28 +377,22 @@ module ActiveRecord
399
377
  transaction do
400
378
  contexts.each do |context|
401
379
  cache = tag_list_cache_on(context)
402
-
380
+
403
381
  cache.each do |owner, list|
404
382
  new_tags = Tag.find_or_create_all_with_like_by_name(list.uniq)
405
- taggings = Tagging.find(:all, :conditions => { :taggable_id => self.id, :taggable_type => self.class.base_class.to_s })
383
+ taggings = Tagging.where({ :taggable_id => self.id, :taggable_type => self.class.base_class.to_s })
406
384
 
407
385
  # Destroy old taggings:
408
386
  if owner
409
387
  old_tags = tags_on(context, owner) - new_tags
410
- old_taggings = Tagging.find(:all, :conditions => { :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 })
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 })
411
389
 
412
- if old_taggings.present?
413
- Tagging.destroy_all :id => old_taggings.map(&:id)
414
- end
390
+ Tagging.destroy_all :id => old_taggings.map(&:id)
415
391
  else
416
392
  old_tags = tags_on(context) - new_tags
417
- old_taggings = Tagging.find(:all, :conditions => { :taggable_id => self.id, :taggable_type => self.class.base_class.to_s, :tag_id => old_tags, :tagger_id => nil, :tagger_type => nil, :context => context })
418
-
419
- if old_taggings.present?
420
- Tagging.destroy_all :id => old_taggings.map(&:id)
421
- end
393
+ base_tags.delete(*old_tags)
422
394
  end
423
-
395
+
424
396
  new_tags.reject! { |tag| taggings.any? { |tagging|
425
397
  tagging.tag_id == tag.id &&
426
398
  tagging.tagger_id == (owner ? owner.id : nil) &&
@@ -428,17 +400,26 @@ module ActiveRecord
428
400
  tagging.context == context
429
401
  }
430
402
  }
431
-
403
+
432
404
  # create new taggings:
433
405
  new_tags.each do |tag|
434
406
  Tagging.create!(:tag_id => tag.id, :context => context, :tagger => owner, :taggable => self)
435
407
  end
436
408
  end
437
409
  end
438
- end
410
+ end
439
411
 
440
412
  true
441
413
  end
414
+
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)
418
+ end
419
+
420
+ reload_without_tag_list(*args)
421
+ end
422
+
442
423
  end
443
424
  end
444
425
  end