0

我有一些模型要显示在分页列表(使用 will_paginate)中,按使用 Globalize 翻译的列排序。

要求说必须能够以任何语言创建对象,并且如果当前语言环境没有可用的翻译,则以预定义的顺序回退到任何其他语言。

我遇到的问题是,如果我在翻译表上加入表,并且翻译是混合的,will_paginate 失败,因为即使有不同的调用,#count 计算错误,AR Relation 上的#limit 不会按预期工作。

例如:

我有一个 Exhibitor 模型,它具有来自 Globalize 的相应 Exhibitor::Translation ,并且 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 仍然显示错误的计数并且不显示导航链接。

4

1 回答 1

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 查询。

于 2017-05-04T13:59:19.313 回答