Skip to content

Commit

Permalink
Configuration option to allow for case-sensitive tags
Browse files Browse the repository at this point in the history
When the strict_case_match flag is on, LIKE queries are not used to
find_or_create tags.
  • Loading branch information
Colin Shield committed Jul 20, 2012
1 parent 1884af8 commit 954a818
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 9 deletions.
3 changes: 3 additions & 0 deletions README.rdoc
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ If you want tags to be saved parametrized (you can redefine to_param as well):


ActsAsTaggableOn.force_parameterize = true ActsAsTaggableOn.force_parameterize = true


If you would like tags to be case-sensitive and not use LIKE queries for creation:

ActsAsTaggableOn.strict_case_match = true


== Contributors == Contributors


Expand Down
3 changes: 3 additions & 0 deletions lib/acts-as-taggable-on.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ module ActsAsTaggableOn
mattr_accessor :force_parameterize mattr_accessor :force_parameterize
@@force_parameterize = false @@force_parameterize = false


mattr_accessor :strict_case_match
@@strict_case_match = false

mattr_accessor :remove_unused_tags mattr_accessor :remove_unused_tags
self.remove_unused_tags = false self.remove_unused_tags = false


Expand Down
30 changes: 21 additions & 9 deletions lib/acts_as_taggable_on/tag.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@ class Tag < ::ActiveRecord::Base
### SCOPES: ### SCOPES:


def self.named(name) def self.named(name)
where(["lower(name) = ?", name.downcase]) if ActsAsTaggableOn.strict_case_match
where(["name = ?", name])
else
where(["lower(name) = ?", name.downcase])
end
end end


def self.named_any(list) def self.named_any(list)
where(list.map { |tag| sanitize_sql(["lower(name) = ?", tag.to_s.mb_chars.downcase]) }.join(" OR ")) if ActsAsTaggableOn.strict_case_match
where(list.map { |tag| sanitize_sql(["name = ?", tag.to_s.mb_chars]) }.join(" OR "))
else
where(list.map { |tag| sanitize_sql(["lower(name) = ?", tag.to_s.mb_chars.downcase]) }.join(" OR "))
end
end end


def self.named_like(name) def self.named_like(name)
Expand All @@ -35,7 +43,11 @@ def self.named_like_any(list)
### CLASS METHODS: ### CLASS METHODS:


def self.find_or_create_with_like_by_name(name) def self.find_or_create_with_like_by_name(name)
named_like(name).first || create(:name => name) if (ActsAsTaggableOn.strict_case_match)
self.find_or_create_all_with_like_by_name([name]).first
else
named_like(name).first || create(:name => name)
end
end end


def self.find_or_create_all_with_like_by_name(*list) def self.find_or_create_all_with_like_by_name(*list)
Expand All @@ -45,9 +57,9 @@ def self.find_or_create_all_with_like_by_name(*list)


existing_tags = Tag.named_any(list).all existing_tags = Tag.named_any(list).all
new_tag_names = list.reject do |name| new_tag_names = list.reject do |name|
name = comparable_name(name) name = comparable_name(name)
existing_tags.any? { |tag| comparable_name(tag.name) == name } existing_tags.any? { |tag| comparable_name(tag.name) == name }
end end
created_tags = new_tag_names.map { |name| Tag.create(:name => name) } created_tags = new_tag_names.map { |name| Tag.create(:name => name) }


existing_tags + created_tags existing_tags + created_tags
Expand All @@ -69,9 +81,9 @@ def count


class << self class << self
private private
def comparable_name(str) def comparable_name(str)
str.mb_chars.downcase.to_s str.mb_chars.downcase.to_s
end end
end end
end end
end end
29 changes: 29 additions & 0 deletions spec/acts_as_taggable_on/tag_spec.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -150,4 +150,33 @@


end end


describe "when using strict_case_match" do
before do
ActsAsTaggableOn.strict_case_match = true
end

after do
ActsAsTaggableOn.strict_case_match = false
end

it "should find by name" do
ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("awesome").should == @tag
end

it "should find by name case sensitively" do
tag_count = ActsAsTaggableOn::Tag.count
tag = ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("AWESOME")

ActsAsTaggableOn::Tag.count.should == tag_count + 1
tag.name.should == "AWESOME"
end

it "should have a named_scope named(something) that matches exactly" do
uppercase_tag = ActsAsTaggableOn::Tag.create(:name => "Cool")
@tag.name = "cool"
@tag.save!
ActsAsTaggableOn::Tag.named('cool').should include(@tag)
ActsAsTaggableOn::Tag.named('cool').should_not include(uppercase_tag)
end
end
end end

0 comments on commit 954a818

Please sign in to comment.