Rails通过带有回退的翻译列全球化排序对象,并且{_ 44}}

时间:2017-04-27 11:41:12

标签: ruby-on-rails activerecord will-paginate globalize

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

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

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

例如:

我有参展商模型及相应的参展商:: Globalize的翻译,参展商对象可以在任何或所有配置的区域设置中翻译。

Exhibitor.with_translations.order(:sort_string).limit(2) 

只返回一个对象,因为第一个参展商对象有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 order records by translated attributes and taking fallbacks into consideration

但是will_paginate仍会显示错误的计数,并且不会显示导航链接。

1 个答案:

答案 0 :(得分: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作为外​​部值(此时此查询没有任何用户输入)

对于&gt; 2个语言环境使用多个连接子句,如上面的原始SQL查询。