Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails collection ordering doesn't works as expected with UTF-8 string

Rails collection ordering doesn't works as expected with UTF-8 string:

> University.order('abbr asc').map(&:abbr)
=> ["Б", "В", "А"]

It should be

> University.order('abbr asc').map(&:abbr)
=> ["А", "Б", "В"]

What am I missing?

Rails 4.1.8 with ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]

like image 223
Stepan Kuzmin Avatar asked May 16 '15 09:05

Stepan Kuzmin


2 Answers

This is most likely a collation settings issue with PostgreSQL:

The collation feature allows specifying the sort order and character classification behavior of data per-column, or even per-operation. This alleviates the restriction that the LC_COLLATE and LC_CTYPE settings of a database cannot be changed after its creation.

You can try and fix the collation of a column with a Rails migration. Something like this:

class FixCollationForAbbr < ActiveRecord::Migration
  def up
    execute 'ALTER TABLE universities ALTER COLUMN abbr TYPE varchar COLLATE "ru_RU";' 
  end
end

You should probably also add collation information to your database.yml:

defaults: &defaults
  adapter: postgresql
  encoding: utf8
  collation: ru_RU.utf8
  ctype: ru_RU.utf8

Here is how the database.yml settings affect table creation with PostgreSQL:

def create_database(name, options = {})
  options = { encoding: 'utf8' }.merge!(options.symbolize_keys)

  option_string = options.inject("") do |memo, (key, value)|
    memo += case key
    ...snip...
    when :encoding
      " ENCODING = '#{value}'"
    when :collation
      " LC_COLLATE = '#{value}'"
    when :ctype
      " LC_CTYPE = '#{value}'"
    ...snip...
    end
  end

  execute "CREATE DATABASE #{quote_table_name(name)}#{option_string}"
end
like image 57
Casper Avatar answered Oct 08 '22 11:10

Casper


If you use the same locale when sorting, try out the ffi-icu gem. This part of the docs is most relevant to you.

There is also sort_alphabetical gem, but it relies on NFD decomposition so it may not work with all characters.

like image 30
Neven Rakonić Avatar answered Oct 08 '22 12:10

Neven Rakonić