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 +1 -1
- data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +27 -12
- data/lib/acts_as_taggable_on/tag.rb +17 -5
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +25 -3
- data/spec/acts_as_taggable_on/tag_spec.rb +27 -0
- data/spec/acts_as_taggable_on/taggable_spec.rb +2 -2
- data/spec/acts_as_taggable_on/tagger_spec.rb +3 -3
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.1
|
@@ -390,21 +390,36 @@ module ActiveRecord
|
|
390
390
|
end
|
391
391
|
|
392
392
|
def save_tags
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
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
|
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
|
-
|
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
|
50
|
-
@taggable.skill_list.include
|
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
|
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.
|
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-
|
12
|
+
date: 2010-02-06 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|