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 запросе выше.

Другие вопросы по тегам