Skip to content

Commit

Permalink
Use database's lower function and unicode downcase for multibyte tag …
Browse files Browse the repository at this point in the history
…names
  • Loading branch information
leo-souza committed Mar 20, 2014
1 parent 68a17c8 commit b50da9b
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 12 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -25,7 +25,7 @@ As such, a _Feature_ would map to either major or minor. A _bug fix_ to a patch.
* [@rgould #417 Let '.count' work when tagged_with is accompanied by a group clause](https://github.com/mbleigh/acts-as-taggable-on/pull/417)
* [@developer88 #461 Move 'Distinct' out of select string and use .uniq instead](https://github.com/mbleigh/acts-as-taggable-on/pull/461)
* [@gerard-leijdekkers #473 Fixed down migration index name](https://github.com/mbleigh/acts-as-taggable-on/pull/473)
* [@leo-souza #492 Fix downcasing of unicode tag names](https://github.com/mbleigh/acts-as-taggable-on/pull/492)
* [@leo-souza #498 Use database's lower function for case-insensitive match](https://github.com/mbleigh/acts-as-taggable-on/pull/498)
* Misc
* [@billychan #463 Thread safe support](https://github.com/mbleigh/acts-as-taggable-on/pull/463)
* [@billychan #386 Add parse:true instructions to README](https://github.com/mbleigh/acts-as-taggable-on/pull/386)
Expand Down
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -340,6 +340,8 @@ If you want to change the default delimiter (it defaults to ','). You can also p
ActsAsTaggableOn.delimiter = ','
```

*NOTE: SQLite by default can't upcase or downcase multibyte characters, resulting in unwanted behavior. Load the SQLite ICU extension for proper handle of such characters. [See docs](http://www.sqlite.org/src/artifact?ci=trunk&filename=ext/icu/README.txt)*

## Contributors

We have a long list of valued contributors. [Check them all](https://github.com/mbleigh/acts-as-taggable-on/contributors)
Expand Down
27 changes: 16 additions & 11 deletions lib/acts_as_taggable_on/tag.rb
Expand Up @@ -24,9 +24,9 @@ def validates_name_uniqueness?

def self.named(name)
if ActsAsTaggableOn.strict_case_match
where(["name = #{binary}?", name])
where(["name = #{binary}?", as_8bit_ascii(name)])
else
where(["lower(name) = ?", name.downcase])
where(["LOWER(name) = LOWER(?)", as_8bit_ascii(unicode_downcase(name))])
end
end

Expand All @@ -38,8 +38,7 @@ def self.named_any(list)
where(clause)
else
clause = list.map { |tag|
lowercase_ascii_tag = as_8bit_ascii(tag, true)
sanitize_sql(["lower(name) = ?", lowercase_ascii_tag])
sanitize_sql(["LOWER(name) = LOWER(?)", as_8bit_ascii(unicode_downcase(tag))])
}.join(" OR ")
where(clause)
end
Expand Down Expand Up @@ -101,23 +100,29 @@ class << self

def comparable_name(str)
if ActsAsTaggableOn.strict_case_match
as_8bit_ascii(str)
str
else
as_8bit_ascii(str, true)
unicode_downcase(str.to_s)
end
end

def binary
using_mysql? ? "BINARY " : nil
end

def as_8bit_ascii(string, downcase=false)
string = string.to_s.dup.mb_chars
string.downcase! if downcase
def unicode_downcase(string)
if ActiveSupport::Multibyte::Unicode.respond_to?(:downcase)
ActiveSupport::Multibyte::Unicode.downcase(string)
else
ActiveSupport::Multibyte::Chars.new(string).downcase.to_s
end
end

def as_8bit_ascii(string)
if defined?(Encoding)
string.to_s.force_encoding('BINARY')
string.to_s.dup.force_encoding('BINARY')
else
string.to_s
string.to_s.mb_chars
end
end
end
Expand Down

0 comments on commit b50da9b

Please sign in to comment.