acts-as-taggable-on 1.1.0 → 1.1.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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.1.1
@@ -390,21 +390,36 @@ module ActiveRecord
390
390
  end
391
391
 
392
392
  def save_tags
393
- (custom_contexts + self.class.tag_types.map(&:to_s)).each do |tag_type|
394
- tag_list_cache = tag_list_cache_on(tag_type)
395
- for owner, tag_list in tag_list_cache
396
- new_tag_names = tag_list - tags_on(tag_type, owner).map(&:name)
397
- old_tags = tags_on(tag_type, owner).reject { |tag| tag_list.include?(tag.name) }
398
- transaction do
399
- base_tags.delete(*old_tags) if old_tags.any?
400
- new_tag_names.each do |new_tag_name|
401
- new_tag = Tag.find_or_create_with_like_by_name(new_tag_name)
402
- Tagging.create(:tag_id => new_tag.id, :context => tag_type,
403
- :taggable => self, :tagger => owner)
393
+ contexts = custom_contexts + self.class.tag_types.map(&:to_s)
394
+
395
+ transaction do
396
+ contexts.each do |context|
397
+ cache = tag_list_cache_on(context)
398
+
399
+ cache.each do |owner, list|
400
+ new_tags = Tag.find_or_create_all_with_like_by_name(list.uniq)
401
+
402
+ # Destroy old taggings:
403
+ if owner
404
+ old_tags = tags_on(context, owner) - new_tags
405
+ old_taggings = taggings.find(:all, :conditions => { :tag_id => old_tags, :tagger_id => owner, :tagger_type => owner.class.to_s, :context => context })
406
+ old_taggings.each(&:destroy)
407
+ else
408
+ old_tags = tags_on(context) - new_tags
409
+ base_tags.delete(*old_tags)
410
+ end
411
+
412
+ new_tags.reject! { |tag| taggings.any? { |tagging| tagging.tag == tag &&
413
+ tagging.tagger == owner &&
414
+ tagging.context == context } }
415
+
416
+ # create new taggings:
417
+ new_tags.each do |tag|
418
+ taggings.create!(:tag_id => tag.id, :context => context, :tagger => owner)
404
419
  end
405
420
  end
406
421
  end
407
- end
422
+ end
408
423
 
409
424
  true
410
425
  end
@@ -13,17 +13,29 @@ class Tag < ActiveRecord::Base
13
13
 
14
14
  ### NAMED SCOPES:
15
15
 
16
- named_scope :named, lambda { |name| { :conditions => ["name = ?", name] } }
16
+ named_scope :named, lambda { |name| { :conditions => ["name LIKE ?", name] } }
17
+ named_scope :named_any, lambda { |list| { :conditions => list.map { |tag| sanitize_sql(["name LIKE ?", tag.to_s]) }.join(" OR ") } }
17
18
  named_scope :named_like, lambda { |name| { :conditions => ["name LIKE ?", "%#{name}%"] } }
18
- named_scope :named_like_any, lambda { |list| { :conditions => list.map { |tag| sanitize_sql(["name LIKE ?", tag.to_s]) }.join(" OR ") } }
19
+ named_scope :named_like_any, lambda { |list| { :conditions => list.map { |tag| sanitize_sql(["name LIKE ?", "%#{tag.to_s}%"]) }.join(" OR ") } }
19
20
 
20
- ### METHODS:
21
+ ### CLASS METHODS:
21
22
 
22
- # LIKE is used for cross-database case-insensitivity
23
23
  def self.find_or_create_with_like_by_name(name)
24
- find(:first, :conditions => ["name LIKE ?", name]) || create(:name => name)
24
+ named_like(name).first || create(:name => name)
25
25
  end
26
26
 
27
+ def self.find_or_create_all_with_like_by_name(*list)
28
+ list = [list].flatten
29
+
30
+ existing_tags = Tag.named_any(list).all
31
+ new_tag_names = list.reject { |name| existing_tags.any? { |tag| tag.name.downcase == name.downcase } }
32
+ created_tags = new_tag_names.map { |name| Tag.create(:name => name) }
33
+
34
+ existing_tags + created_tags
35
+ end
36
+
37
+ ### INSTANCE METHODS:
38
+
27
39
  def ==(object)
28
40
  super || (object.is_a?(Tag) && name == object.name)
29
41
  end
@@ -1,8 +1,11 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
2
 
3
3
  describe "acts_as_tagger" do
4
+ before(:each) do
5
+ [TaggableUser, TaggableModel, Tagging, Tag].each(&:destroy_all)
6
+ end
7
+
4
8
  context "Tagger Method Generation" do
5
-
6
9
  before(:each) do
7
10
  @tagger = TaggableUser.new()
8
11
  end
@@ -78,9 +81,28 @@ describe "acts_as_tagger" do
78
81
  @tagger.tag(@taggable, :with=>'this, and, that', :on=>:foo_boo, :force=>false) rescue
79
82
  @taggable.tag_list_on(:foo_boo).should be_empty
80
83
  end
81
-
82
84
  end
83
-
85
+
86
+ context "when called by multiple tagger's" do
87
+ before(:each) do
88
+ @user_x = TaggableUser.new
89
+ @user_y = TaggableUser.new
90
+ @taggable = TaggableModel.new(:name => 'acts_as_taggable_on', :tag_list => 'plugin')
91
+
92
+ @user_x.tag(@taggable, :with => 'ruby, rails', :on => :tags)
93
+ @user_y.tag(@taggable, :with => 'ruby, plugin', :on => :tags)
94
+ end
95
+
96
+ it "should not delete other taggers tags" do
97
+ @user_y.tag(@taggable, :with => '', :on => :tags)
98
+ @taggable.all_tags_list_on(:tags).should include('ruby')
99
+ end
100
+
101
+ it "should not delete original tags" do
102
+ @user_y.tag(@taggable, :with => '', :on => :tags)
103
+ @taggable.all_tags_list_on(:tags).should include('plugin')
104
+ end
105
+ end
84
106
  end
85
107
 
86
108
  end
@@ -38,6 +38,33 @@ describe Tag do
38
38
  }.should change(Tag, :count).by(1)
39
39
  end
40
40
  end
41
+
42
+ describe "find or create all by any name" do
43
+ before(:each) do
44
+ @tag.name = "awesome"
45
+ @tag.save
46
+ end
47
+
48
+ it "should find by name" do
49
+ Tag.find_or_create_all_with_like_by_name("awesome").should == [@tag]
50
+ end
51
+
52
+ it "should find by name case insensitive" do
53
+ Tag.find_or_create_all_with_like_by_name("AWESOME").should == [@tag]
54
+ end
55
+
56
+ it "should create by name" do
57
+ lambda {
58
+ Tag.find_or_create_all_with_like_by_name("epic")
59
+ }.should change(Tag, :count).by(1)
60
+ end
61
+
62
+ it "should find or create by name" do
63
+ lambda {
64
+ Tag.find_or_create_all_with_like_by_name("awesome", "epic").map(&:name).should == ["awesome", "epic"]
65
+ }.should change(Tag, :count).by(1)
66
+ end
67
+ end
41
68
 
42
69
  it "should require a name" do
43
70
  @tag.valid?
@@ -46,8 +46,8 @@ describe "Taggable" do
46
46
  @taggable.tag_list = "ruby, bob, charlie"
47
47
  @taggable.save
48
48
  @taggable.reload
49
- @taggable.skill_list.include?("ruby").should be_true
50
- @taggable.skill_list.include?("bob").should be_false
49
+ @taggable.skill_list.should include("ruby")
50
+ @taggable.skill_list.should_not include("bob")
51
51
  end
52
52
 
53
53
  it "should be able to remove tags through list alone" do
@@ -24,10 +24,10 @@ describe "Tagger" do
24
24
  @user2.tag(@taggable, :with => 'java, python, lisp, ruby', :on => :tags)
25
25
  }.should change(Tagging, :count).by(6)
26
26
 
27
- @user.owned_tags.map(&:name).should == %w(ruby scheme)
27
+ @user.owned_tags.map(&:name).sort.should == %w(ruby scheme)
28
28
  @user2.owned_tags.map(&:name).sort.should == %w(java python lisp ruby).sort
29
- @taggable.tags_from(@user).should == %w(ruby scheme)
30
- @taggable.tags_from(@user2).should == %w(java python lisp ruby)
29
+ @taggable.tags_from(@user).sort.should == %w(ruby scheme)
30
+ @taggable.tags_from(@user2).sort.should == %w(java lisp python ruby)
31
31
  @taggable.all_tags_list_on(:tags).sort.should == %w(ruby scheme java python lisp).sort
32
32
  @taggable.all_tags_on(:tags).size.should == 6
33
33
  end
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: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-03 00:00:00 +01:00
12
+ date: 2010-02-06 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15