我尝试使用rails 4进行非常简单的查询,但我遇到了意外问题......
我有一个带有翻译表的Country
模型(通过globalize gem)。我想获取当前区域设置中的每个国家/地区名称,国家/地区ID以及short_code
我存储在Country
模型中的countries = Country.select('countries.id, countries.short_code,
country_translations.name').joins(:translations)
。
我的第一个方法是这句话:
SELECT countries.id, countries.short_code, country_translations.name
FROM `countries` INNER JOIN `country_translations`
ON `country_translations`.`country_id` = `countries`.`id`
这会生成此SQL:
countries
这似乎是一个正确的查询,如果我在数据库控制台中运行它,它会获取我想要的数据。问题来了,因为我需要序列化SELECT `country_translations`.* FROM `country_translations` WHERE `country_translations`.`country_id` = 1 [["country_id", 1]]
[...]
SELECT `country_translations`.* FROM `country_translations` WHERE `country_translations`.`country_id` = 238 [["country_id", 238]]
SELECT `country_translations`.* FROM `country_translations` WHERE `country_translations`.`country_id` = 239 [["country_id", 239]]
。它为每个国家/地区运行查询:
include
为了避免n + 1问题,我尝试countries = Country.select('countries.id, countries.short_code,
country_translations.name').includes(:translations).joins(:translations)
查询翻译:
country
这就像一个魅力,只在一个查询中返回所有内容。问题是它从country_translations
和SELECT countries.id, countries.short_code, country_translations.name,
`countries`.`id` AS t0_r0, `countries`.`population` AS t0_r1,
`countries`.`short_code` AS t0_r2,
`countries`.`lat` AS t0_r3,
`countries`.`lng` AS t0_r4,
`countries`.`range` AS t0_r5,
`countries`.`tilt` AS t0_r6,
`countries`.`heading` AS t0_r7,
`countries`.`country_code_short` AS t0_r8,
`countries`.`date_format` AS t0_r9,
...
`countries`.`created_at` AS t0_r12,
`countries`.`updated_at` AS t0_r13,
`country_translations`.`id` AS t1_r0,
`country_translations`.`country_id` AS t1_r1,
`country_translations`.`locale` AS t1_r2,
`country_translations`.`created_at` AS t1_r3,
`country_translations`.`updated_at` AS t1_r4,
`country_translations`.`name` AS t1_r5,
`country_translations`.`language` AS t1_r6,
`country_translations`.`currency` AS t1_r7,
`country_translations`.`capital` AS t1_r8,
`country_translations`.`slug` AS t1_r9
FROM `countries`
INNER JOIN `country_translations`
ON `country_translations`.`country_id` = `countries`.`id`
获取了每个属性,忽略了select语句!
let chars = NSCharacterSet(charactersInString: "() \n")
text.componentsSeparatedByCharactersInSet(chars).joinWithSeparator("")
这带来了另一个问题,因为序列化对于这么多字段来说更复杂......
我错过了什么?我怎样才能得到我需要的那三个领域?
答案 0 :(得分:1)
似乎您正在调用country.name
并期望ActiveRecord结果中的name
属性,而globalize gem正在调用name
< em>方法 - 触发n + 1。
使用ActiveRecord的includes方法是解决n + 1的一种方法,如你所提到的那样,但是会产生令人讨厌的副作用,即否定select
语句并构建更大的ActiveRecord ::关系对象不是必需的。另外,您已经有效地选择了所需的字段。
AbM's comment以上指向解决方案;但是country_translations.name
在您的查询中已经将name
别名为countries = Country.select([
'countries.id',
'countries.short_code',
'country_translations.name AS country_translation_name'
])
,为了澄清,我建议如下:
countries
当迭代country.id # => 840
country.short_code # => "US"
country.country_translation_name # => "United States of America"
时,您现在可以调用:
{{1}}