我想要在分页列表中显示一些模型(使用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仍会显示错误的计数,并且不会显示导航链接。
答案 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查询。