Rails Глобализируйте объекты сортировки по переведенному столбцу с помощью fallbacks и will_paginate.
У меня есть несколько моделей, которые я хочу отобразить в разбивке по страницам (с will_paginate), отсортированной по столбцу, переведенному с помощью Globalize.
В требованиях говорится, что должна быть возможность создавать объекты на любом языке, и если нет перевода для текущей локали, можно использовать любой другой в предопределенном порядке.
Проблема, с которой я сталкиваюсь, состоит в том, что, если я присоединяюсь к таблице в таблице перевода, и переводы смешаны, will_paginate завершится неудачно, потому что даже при отдельном вызове #count вычисляется неправильно, а #limit для AR Relation не работать как положено.
Например:
У меня есть модель Exhibitor с соответствующим Exhibitor::Translation от Globalize, и объекты Exhibitor могут иметь переводы в любой или во всех настроенных локалях.
Exhibitor.with_translations.order(:sort_string).limit(2)
возвращает только один объект, потому что первый объект Exhibitor имеет 2 перевода, и даже вызов #distinct не меняет этого, что означает, что will_paginate запутывается и
Я думаю, что я хочу что-то вроде этого:
SELECT exhibitors.id,translations.sort_string
FROM exhibitors
INNER JOIN
exhibitor_translations translations ON translations.exhibitor_id =
exhibitors.id
WHERE translations.locale = 'en' OR translations.locale = 'de' OR
translations.locale = 'fr'
ORDER BY translations.sort_string;
Часть WHERE - это то, где я борюсь, потому что я просто хочу первый существующий перевод, но здесь я возвращаю все доступное для каждого объекта.
Я надеюсь, что это несколько понятное объяснение, все еще пытаюсь точно сформулировать это в моей голове, поэтому, если требуется какое-либо разъяснение, пожалуйста, просто спросите.
Я попробовал несколько вариантов этого решения здесь. Порядок записей Globalize3 по переведенным атрибутам и с учетом откатов
но will_paginate по-прежнему показывает неправильный счетчик и не отображает навигационные ссылки.
1 ответ
Если кто-то столкнется с той же проблемой, я, наконец, решил ее с помощью такого подзапроса:
SELECT DISTINCT
COALESCE(b.exhibitor_id, c.exhibitor_id, a.exhibitor_id) exhibitor_id,
COALESCE(b.sort_string, c.sort_string, a.sort_string) sort_string
FROM exhibitor_translations a
LEFT JOIN
(
SELECT ID, exhibitor_id, sort_string, locale
FROM exhibitor_translations
WHERE locale = 'fr'
) b ON a.exhibitor_id = b.exhibitor_id
LEFT JOIN
(
SELECT ID, exhibitor_id, sort_string, locale
FROM exhibitor_translations
WHERE locale = 'en'
) c ON a.exhibitor_id = c.exhibitor_id;
Код Rails выглядит следующим образом (не окончательный производственный код, но достаточно близко):
entity = Exhibitor
query = entity.all
translation_table = entity.translations_table_name
foreign_key = "#{entity.name.demodulize.underscore}_id"
attribute_name = "sort_string"
subquery = entity.translation_class.select("
DISTINCT
COALESCE(b.id, a.id) id,
COALESCE(b.#{foreign_key}, a.#{foreign_key}) #{foreign_key},
COALESCE(b.#{attribute_name}, a.#{attribute_name}) #{attribute_name}
")
subquery.from("#{translation_table} AS a")
subquery = subquery.joins("
LEFT JOIN
(
SELECT id, #{foreign_key}, #{attribute_name}
FROM #{translation_table}
WHERE locale = '#{I18n.locale}'
) b ON a.id <> b.id AND a.#{foreign_key} = b.#{foreign_key}
")
query = query.joins("INNER JOIN (#{subquery.to_sql}) t ON #{entity.table_name}.id = t.#{foreign_key}")
query.order("t.#{attribute_name} ASC")
Если кто-то захочет использовать это, помните о возможностях SQL-инъекций и используйте ActiveRecord#quote для внешних значений (в данный момент у меня нет пользовательских входов для этого запроса)
Для> 2 локалей используйте несколько предложений объединения, как в сыром sql запросе выше.