yetanothernguyen-acts-as-taggable-on 0.0.4 → 0.0.5

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
- 0.0.4
1
+ 0.0.5
@@ -11,11 +11,11 @@ module ActsAsTaggableOn::Taggable
11
11
  before_save :save_cached_tag_list
12
12
  end
13
13
 
14
- base.initialize_acts_as_taggable_on_cache
14
+ base.intialize_acts_as_taggable_on_cache
15
15
  end
16
16
 
17
17
  module ClassMethods
18
- def initialize_acts_as_taggable_on_cache
18
+ def intialize_acts_as_taggable_on_cache
19
19
  tag_types.map(&:to_s).each do |tag_type|
20
20
  class_eval %(
21
21
  def self.caching_#{tag_type.singularize}_list?
@@ -27,7 +27,7 @@ module ActsAsTaggableOn::Taggable
27
27
 
28
28
  def acts_as_taggable_on(*args)
29
29
  super(*args)
30
- initialize_acts_as_taggable_on_cache
30
+ intialize_acts_as_taggable_on_cache
31
31
  end
32
32
 
33
33
  def caching_tag_list_on?(context)
@@ -61,72 +61,65 @@ module ActsAsTaggableOn::Taggable
61
61
 
62
62
  ## Generate conditions:
63
63
  options[:conditions] = sanitize_sql(options[:conditions]) if options[:conditions]
64
-
64
+
65
65
  start_at_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
66
66
  end_at_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
67
-
67
+
68
68
  taggable_conditions = sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.taggable_type = ?", base_class.name])
69
- taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = ?", options.delete(:id)]) if options[:id]
70
- taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", options.delete(:on).to_s]) if options[:on]
71
-
72
- tagging_conditions = [
69
+ taggable_conditions << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = ?", options.delete(:id)]) if options[:id]
70
+
71
+ conditions = [
73
72
  taggable_conditions,
73
+ options[:conditions],
74
74
  scope[:conditions],
75
75
  start_at_conditions,
76
76
  end_at_conditions
77
77
  ].compact.reverse
78
78
 
79
- tag_conditions = [
80
- options[:conditions]
81
- ].compact.reverse
82
-
83
79
  ## Generate joins:
80
+ tagging_join = "LEFT OUTER JOIN #{ActsAsTaggableOn::Tagging.table_name} ON #{ActsAsTaggableOn::Tag.table_name}.id = #{ActsAsTaggableOn::Tagging.table_name}.tag_id"
81
+ tagging_join << sanitize_sql([" AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", options.delete(:on).to_s]) if options[:on]
82
+
84
83
  taggable_join = "INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id"
85
84
  taggable_join << " AND #{table_name}.#{inheritance_column} = '#{name}'" unless descends_from_active_record? # Current model is STI descendant, so add type checking to the join condition
86
85
 
87
- tagging_joins = [
86
+ joins = [
87
+ tagging_join,
88
88
  taggable_join,
89
89
  scope[:joins]
90
90
  ].compact
91
91
 
92
- tag_joins = [
93
- ].compact
92
+ joins = joins.reverse if ActiveRecord::VERSION::MAJOR < 3
94
93
 
95
- [tagging_joins, tag_joins].each(&:reverse!) if ActiveRecord::VERSION::MAJOR < 3
96
94
 
97
95
  ## Generate scope:
98
- tagging_scope = ActsAsTaggableOn::Tagging.select("#{ActsAsTaggableOn::Tagging.table_name}.tag_id, COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) AS tags_count")
99
- tag_scope = ActsAsTaggableOn::Tag.select("#{ActsAsTaggableOn::Tag.table_name}.*, #{ActsAsTaggableOn::Tagging.table_name}.tags_count AS count").order(options[:order]).limit(options[:limit])
100
-
96
+ scope = ActsAsTaggableOn::Tag.scoped(:select => "#{ActsAsTaggableOn::Tag.table_name}.*, COUNT(*) AS count").order(options[:order]).limit(options[:limit])
97
+
101
98
  # Joins and conditions
102
- tagging_joins.each { |join| tagging_scope = tagging_scope.joins(join) }
103
- tagging_conditions.each { |condition| tagging_scope = tagging_scope.where(condition) }
104
-
105
- tag_joins.each { |join| tag_scope = tag_scope.joins(join) }
106
- tag_conditions.each { |condition| tag_scope = tag_scope.where(condition) }
107
-
99
+ joins.each { |join| scope = scope.joins(join) }
100
+ conditions.each { |condition| scope = scope.where(condition) }
101
+
108
102
  # GROUP BY and HAVING clauses:
109
- at_least = sanitize_sql(['tags_count >= ?', options.delete(:at_least)]) if options[:at_least]
110
- at_most = sanitize_sql(['tags_count <= ?', options.delete(:at_most)]) if options[:at_most]
111
- having = ["COUNT(#{ActsAsTaggableOn::Tagging.table_name}.tag_id) > 0", at_least, at_most].compact.join(' AND ')
112
-
113
- group_columns = "#{ActsAsTaggableOn::Tagging.table_name}.tag_id"
103
+ at_least = sanitize_sql(['COUNT(*) >= ?', options.delete(:at_least)]) if options[:at_least]
104
+ at_most = sanitize_sql(['COUNT(*) <= ?', options.delete(:at_most)]) if options[:at_most]
105
+ having = [at_least, at_most].compact.join(' AND ')
114
106
 
115
107
  if ActiveRecord::VERSION::MAJOR >= 3
116
108
  # Append the current scope to the scope, because we can't use scope(:find) in RoR 3.0 anymore:
117
109
  scoped_select = "#{table_name}.#{primary_key}"
118
- tagging_scope = tagging_scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{select(scoped_select).to_sql})").
119
- group(group_columns).
120
- having(having)
110
+ scope = scope.where("#{ActsAsTaggableOn::Tagging.table_name}.taggable_id IN(#{select(scoped_select).to_sql})")
111
+
112
+ # We have having() in RoR 3.0 so use it:
113
+ having = having.blank? ? "COUNT(*) > 0" : "COUNT(*) > 0 AND #{having}"
114
+ scope = scope.group(grouped_column_names_for(ActsAsTaggableOn::Tag)).having(having)
121
115
  else
122
116
  # Having is not available in 2.3.x:
123
- group_by = "#{group_columns} HAVING COUNT(*) > 0"
117
+ group_by = "#{grouped_column_names_for(ActsAsTaggableOn::Tag)} HAVING COUNT(*) > 0"
124
118
  group_by << " AND #{having}" unless having.blank?
125
- tagging_scope = tagging_scope.group(group_by)
119
+ scope = scope.group(group_by)
126
120
  end
127
121
 
128
- tag_scope = tag_scope.joins("JOIN (#{tagging_scope.to_sql}) AS taggings ON taggings.tag_id = tags.id")
129
- tag_scope
122
+ scope
130
123
  end
131
124
  end
132
125
 
@@ -21,7 +21,7 @@ module ActsAsTaggableOn::Taggable
21
21
 
22
22
  class_eval do
23
23
  has_many context_taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging",
24
- :conditions => ["#{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", tags_type]
24
+ :conditions => ["#{ActsAsTaggableOn::Tagging.table_name}.tagger_id IS NULL AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", tags_type]
25
25
  has_many context_tags, :through => context_taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag"
26
26
  end
27
27
 
@@ -80,18 +80,8 @@ module ActsAsTaggableOn::Taggable
80
80
  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}.id AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"
81
81
 
82
82
  elsif options.delete(:any)
83
- conditions << tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name LIKE ?", t]) }.join(" OR ")
84
-
85
- tagging_join = " JOIN #{ActsAsTaggableOn::Tagging.table_name}" +
86
- " ON #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = #{table_name}.#{primary_key}" +
87
- " AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)}" +
88
- " JOIN #{ActsAsTaggableOn::Tag.table_name}" +
89
- " ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id"
90
-
91
- tagging_join << " AND " + sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.context = ?", context.to_s]) if context
92
- select_clause = "DISTINCT #{table_name}.*" unless context and tag_types.one?
93
-
94
- joins << tagging_join
83
+ tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name LIKE ?", t]) }.join(" OR ")
84
+ conditions << "#{table_name}.#{primary_key} 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}.id AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"
95
85
 
96
86
  else
97
87
  tags = ActsAsTaggableOn::Tag.named_any(tag_list)
@@ -101,7 +91,7 @@ module ActsAsTaggableOn::Taggable
101
91
  safe_tag = tag.name.gsub(/[^a-zA-Z0-9]/, '')
102
92
  prefix = "#{safe_tag}_#{rand(1024)}"
103
93
 
104
- taggings_alias = "#{undecorated_table_name}_taggings_#{prefix}"
94
+ taggings_alias = "#{table_name}_taggings_#{prefix}"
105
95
 
106
96
  tagging_join = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
107
97
  " ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
@@ -113,20 +103,18 @@ module ActsAsTaggableOn::Taggable
113
103
  end
114
104
  end
115
105
 
116
- taggings_alias, tags_alias = "#{undecorated_table_name}_taggings_group", "#{undecorated_table_name}_tags_group"
106
+ taggings_alias, tags_alias = "#{table_name}_taggings_group", "#{table_name}_tags_group"
117
107
 
118
108
  if options.delete(:match_all)
119
109
  joins << "LEFT OUTER JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
120
110
  " ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
121
111
  " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"
122
112
 
123
-
124
- group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}"
125
- group = "#{group_columns} HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
113
+ group = "#{grouped_column_names_for(self)} HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
126
114
  end
127
115
 
128
- scoped(:select => select_clause,
129
- :joins => joins.join(" "),
116
+
117
+ scoped(:joins => joins.join(" "),
130
118
  :group => group,
131
119
  :conditions => conditions.join(" AND "),
132
120
  :order => options[:order],
@@ -188,17 +176,8 @@ module ActsAsTaggableOn::Taggable
188
176
  tag_table_name = ActsAsTaggableOn::Tag.table_name
189
177
  tagging_table_name = ActsAsTaggableOn::Tagging.table_name
190
178
 
191
- opts = ["#{tagging_table_name}.context = ?", context.to_s]
192
- scope = base_tags.where(opts)
193
-
194
- if ActsAsTaggableOn::Tag.using_postgresql?
195
- group_columns = grouped_column_names_for(ActsAsTaggableOn::Tag)
196
- scope = scope.order("max(#{tagging_table_name}.created_at)").group(group_columns)
197
- else
198
- scope = scope.group("#{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key}")
199
- end
200
-
201
- scope.all
179
+ opts = ["#{tagging_table_name}.context = ?", context.to_s]
180
+ base_tags.where(opts).order("max(#{tagging_table_name}.created_at)").group("#{tag_table_name}.id, #{tag_table_name}.name").all
202
181
  end
203
182
 
204
183
  ##
@@ -30,13 +30,9 @@ module ActsAsTaggableOn::Taggable
30
30
 
31
31
  module InstanceMethods
32
32
  def owner_tags_on(owner, context)
33
- if owner.nil?
34
- base_tags.where([%(#{ActsAsTaggableOn::Tagging.table_name}.context = ?), context.to_s]).all
35
- else
36
- base_tags.where([%(#{ActsAsTaggableOn::Tagging.table_name}.context = ? AND
37
- #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = ? AND
38
- #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = ?), context.to_s, owner.id, owner.class.to_s]).all
39
- end
33
+ base_tags.where([%(#{ActsAsTaggableOn::Tagging.table_name}.context = ? AND
34
+ #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = ? AND
35
+ #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = ?), context.to_s, owner.id, owner.class.to_s]).all
40
36
  end
41
37
 
42
38
  def cached_owned_tag_list_on(context)
@@ -42,12 +42,10 @@ module ActsAsTaggableOn::Taggable
42
42
 
43
43
  exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass
44
44
 
45
- group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(klass) : "#{klass.table_name}.#{klass.primary_key}"
46
-
47
45
  klass.scoped({ :select => "#{klass.table_name}.*, COUNT(#{ActsAsTaggableOn::Tag.table_name}.id) AS count",
48
46
  :from => "#{klass.table_name}, #{ActsAsTaggableOn::Tag.table_name}, #{ActsAsTaggableOn::Tagging.table_name}",
49
47
  :conditions => ["#{exclude_self} #{klass.table_name}.id = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id AND #{ActsAsTaggableOn::Tag.table_name}.name IN (?) AND #{ActsAsTaggableOn::Tagging.table_name}.context = ?", tags_to_find, result_context],
50
- :group => group_columns,
48
+ :group => grouped_column_names_for(klass),
51
49
  :order => "count DESC" }.update(options))
52
50
  end
53
51
 
@@ -56,12 +54,10 @@ module ActsAsTaggableOn::Taggable
56
54
 
57
55
  exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass
58
56
 
59
- group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(klass) : "#{klass.table_name}.#{klass.primary_key}"
60
-
61
57
  klass.scoped({ :select => "#{klass.table_name}.*, COUNT(#{ActsAsTaggableOn::Tag.table_name}.id) AS count",
62
58
  :from => "#{klass.table_name}, #{ActsAsTaggableOn::Tag.table_name}, #{ActsAsTaggableOn::Tagging.table_name}",
63
59
  :conditions => ["#{exclude_self} #{klass.table_name}.id = #{ActsAsTaggableOn::Tagging.table_name}.taggable_id AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.id AND #{ActsAsTaggableOn::Tag.table_name}.name IN (?)", tags_to_find],
64
- :group => group_columns,
60
+ :group => grouped_column_names_for(klass),
65
61
  :order => "count DESC" }.update(options))
66
62
  end
67
63
  end
@@ -9,11 +9,7 @@ module ActsAsTaggableOn
9
9
  named_scope :order, lambda { |order| { :order => order } }
10
10
  named_scope :select, lambda { |select| { :select => select } }
11
11
  named_scope :limit, lambda { |limit| { :limit => limit } }
12
- named_scope :readonly, lambda { |readonly| { :readonly => readonly } }
13
-
14
- def self.to_sql
15
- construct_finder_sql({})
16
- end
12
+ named_scope :readonly, lambda { |readonly| { :readonly => readonly } }
17
13
  end
18
14
  end
19
15
  end
@@ -14,10 +14,6 @@ module ActsAsTaggableOn
14
14
  validates_uniqueness_of :name
15
15
 
16
16
  ### SCOPES:
17
-
18
- def self.using_postgresql?
19
- connection.adapter_name == 'PostgreSQL'
20
- end
21
17
 
22
18
  def self.named(name)
23
19
  where(["name #{like_operator} ?", name])
@@ -47,10 +43,7 @@ module ActsAsTaggableOn
47
43
  return [] if list.empty?
48
44
 
49
45
  existing_tags = Tag.named_any(list).all
50
- new_tag_names = list.reject do |name|
51
- name = comparable_name(name)
52
- existing_tags.any? { |tag| comparable_name(tag.name) == name }
53
- end
46
+ new_tag_names = list.reject { |name| existing_tags.any? { |tag| tag.name.mb_chars.downcase == name.mb_chars.downcase } }
54
47
  created_tags = new_tag_names.map { |name| Tag.create(:name => name) }
55
48
 
56
49
  existing_tags + created_tags
@@ -73,12 +66,9 @@ module ActsAsTaggableOn
73
66
  class << self
74
67
  private
75
68
  def like_operator
76
- using_postgresql? ? 'ILIKE' : 'LIKE'
77
- end
78
-
79
- def comparable_name(str)
80
- RUBY_VERSION >= "1.9" ? str.downcase : str.mb_chars.downcase
69
+ connection.adapter_name == 'PostgreSQL' ? 'ILIKE' : 'LIKE'
81
70
  end
82
71
  end
72
+
83
73
  end
84
74
  end
@@ -4,7 +4,6 @@ describe "Taggable" do
4
4
  before(:each) do
5
5
  clean_database!
6
6
  @taggable = TaggableModel.new(:name => "Bob Jones")
7
- @taggables = [@taggable, TaggableModel.new(:name => "John Doe")]
8
7
  end
9
8
 
10
9
  it "should have tag types" do
@@ -69,22 +68,6 @@ describe "Taggable" do
69
68
  @taggable.should have(2).skills
70
69
  end
71
70
 
72
- it "should be able to select taggables by subset of tags using ActiveRelation methods" do
73
- @taggables[0].tag_list = "bob"
74
- @taggables[1].tag_list = "charlie"
75
- @taggables[0].skill_list = "ruby"
76
- @taggables[1].skill_list = "css"
77
- @taggables.each{|taggable| taggable.save}
78
-
79
- @found_taggables_by_tag = TaggableModel.joins(:tags).where(:tags => {:name => ["bob"]})
80
- @found_taggables_by_skill = TaggableModel.joins(:skills).where(:tags => {:name => ["ruby"]})
81
-
82
- @found_taggables_by_tag.should include @taggables[0]
83
- @found_taggables_by_tag.should_not include @taggables[1]
84
- @found_taggables_by_skill.should include @taggables[0]
85
- @found_taggables_by_skill.should_not include @taggables[1]
86
- end
87
-
88
71
  it "should be able to find by tag" do
89
72
  @taggable.skill_list = "ruby, rails, css"
90
73
  @taggable.save
data/spec/spec_helper.rb CHANGED
@@ -13,7 +13,7 @@ begin
13
13
  Bundler.setup
14
14
  rescue Bundler::GemNotFound
15
15
  raise RuntimeError, "Bundler couldn't find some gems." +
16
- "Did you run \`bundlee install\`?"
16
+ "Did you run `bundle install`?"
17
17
  end
18
18
 
19
19
  Bundler.require
@@ -57,4 +57,4 @@ def clean_database!
57
57
  end
58
58
  end
59
59
 
60
- clean_database!
60
+ clean_database!
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yetanothernguyen-acts-as-taggable-on
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 4
10
- version: 0.0.4
9
+ - 5
10
+ version: 0.0.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Michael Bleigh