Можно ли добавить индекс агностики на основе функций через миграцию Rails/ActiveRecord?

У меня есть модель ActiveRecord:

create_table "books" do |t|
  t.string "title"
end

class Book < ActiveRecord::Base
  default_scope :order => 'lower(title) DESC'
end

Как вы можете видеть, я хочу сортировать по строчной форме атрибута title, но это накладывает удар производительности на уровне базы данных. Этот удар может быть исправлен по-разному с различными базами данных. Например, в PostgreSQL или Oracle вы создаете индекс на основе функций:

CREATE INDEX lowercase_book_title_index ON book (lower(title));

SQLite3 не имеет функциональных индексов, поэтому вам нужно указать сортировку:

CREATE INDEX lowercase_book_title_index ON book (title COLLATE NOCASE);

Я не рассматривал, как вы это делаете с MySQL, но я уверен, что есть способ (сортировки? виртуальные столбцы?).

В любом случае я хотел бы сделать это в правильном режиме Rails с миграцией агностики базы данных. Я могу, конечно, создать простой индекс:

add_index :books, :title

Но индекс, который он генерирует, чувствителен к регистру. Я понимаю, что могу написать миграцию, зависящую от базы данных, но она не очень элегантная. Это также непрактично - я часто нахожу себя использующим SQLite3 на своих рабочих станциях разработки и PostgreSQL в производстве. Доступные опции для add_index имеют дело с именем индекса, его уникальностью и длиной. Могу ли я игнорировать способ выполнить то, что я пытаюсь сделать здесь?

Ответ 1

Короткий ответ: не

Длинный ответ: нет, потому что не все базы данных поддерживают его, что поддерживает Rails, или совсем другим способом. Если вы уверены, что все механизмы базы данных поддерживают его, тогда файл запросит функцию для разработчиков ActiveRecord.

Помните: в миграциях ActiveRecord вы можете делать только то, что поддерживает весь механизм базы данных, для данных базы данных нужны отдельные инициализации из миграций.

Я рекомендую настроить эту сортировку из разделенной задачи rake, которая запускается после db: migrate. В моих более крупных приложениях я использую rake setup, где я могу выполнить следующие шаги.

Ответ 2

У меня никогда не было проблем с подобной сортировкой. В основном, вы хотите, чтобы результаты сортировались следующим образом:

"A bad title"
"A better title"
"a good title"
"An excellent title"

Если это правильно и вы собираетесь с mysql, вы можете указать сортировку в базе данных .yml, попробуйте:

production:
  adapter: mysql2 # or mysql for rails < 3
  host: ...
  database: ...
  username: ...
  encoding: utf8 # or whatever you are using
  collation: utf8_general_ci # or whatever fits your language and encoding

utf8_general_ci означает "сопоставлять с utf8 независимым от языка способом и нечувствителен к регистру".

Это должно сделать трюк.