我一直遇到 Rails 3 Active Record Query Interface 的问题。我有一个查找表 (lookups)、一个主表 (through_references) 和一个名为 through_tables 的直通/连接表。因此,这是我使用 has_many :through 设置的 HABTM 配置。
更新:这里需要特别注意的是,当我进行这些联接时,我一直在加入 ID,以提供记录过滤。这似乎不适用于 Active Record Query Interface。如果您不想看到我辛苦的血腥细节,您可以跳到下面查看我的解决方法。
我们还将有一些主要项目(through_references 表)应该能够有任何查找项的组合,并且能够方便地通过复选框单击相关的查找项。
我已经在github上发布了代码。github源代码上有很多解释。要查看结果,请转到查找索引页面。请注意,您将需要使用脚手架代码创建记录。
我还在heroku上启动并运行了代码,并提供了更多解释和示例。
class Lookup < ActiveRecord::Base
has_many :fk_references
has_many :through_tables
has_many :through_references, :through => :through_tables
attr_accessible :name, :value
end
class ThroughTable < ActiveRecord::Base
belongs_to :through_reference
belongs_to :lookup
attr_accessible :description, :through_reference_id, :lookup_id
end
class ThroughReference < ActiveRecord::Base
has_many :through_tables
has_many :lookups, :through => :through_tables
attr_accessible :description
end
如果我们想要列出所有查找项目以及与之对应的主要项目,我们可以将“查找”表与主要项目(through_references)表连接起来。对应的SQL:
SELECT * FROM lookups
LEFT OUTER JOIN through_tables ON (lookups.id = through_tables.lookup_id AND through_tables.through_reference_id = 1)
LEFT OUTER JOIN through_references ON through_references.id = through_tables.through_reference_id
ORDER BY lookups.id
返回记录:
1;“Lookup Item 1”;“1”;“2012-06-06 17:14:40.819791”;“2012-06-06 17:14:40.819791”;1;1;1;“Main Item 1 has Lookup item 1”;“2012-06-06 17:17:31.355425”;“2012-06-06 17:17:31.355425”;1;“Main Item 1”;“2012-06-06 17:16:30.004375”;“2012-06-06 17:16:30.004375”
2;“Lookup Item 2”;“2”;“2012-06-06 17:14:59.584756”;“2012-06-06 17:14:59.584756”;;;;“”;“”;“”;;“”;“”;“”
3;“Lookup Item 3”;“3”;“2012-06-06 17:15:14.700239”;“2012-06-06 17:15:14.700239”;2;1;3;“Main Item 1 has Lookup item 3”;“2012-06-06 17:17:53.169715”;“2012-06-06 17:17:53.169715”;1;“Main Item 1”;“2012-06-06 17:16:30.004375”;“2012-06-06 17:16:30.004375”
这是我所期望的。
=== 使用自定义左连接的活动记录查询接口
Lookup.joins(“LEFT OUTER JOIN through_tables ON (lookups.id = through_tables.lookup_id AND through_tables.through_reference_id = 1)” ).includes(:through_references).order(‘lookups.id’)
从 Active Record 查询界面返回的内容(注意我在 Active Record 层次结构中向下导航):
Lookup ID Lookup Name Lookup Value Through Table ID Through Table Description Main Item ID Main Item Description
1 Lookup Item 1 1 1 Main Item 1 has Lookup item 1 1 Main Item 1
1 Lookup Item 1 1 3 Main Item 2 has Lookup item 1 2 Main Item 2
2 Lookup Item 2 2 4 Main Item 2 has Lookup item 2 2 Main Item 2
3 Lookup Item 3 3 2 Main Item 1 has Lookup item 3 1 Main Item 1
这不是我所期望的。
我们这里的内容与简单的左连接(没有 AND 子句)相同。这告诉我在 Active Record 查询界面中忽略了 AND 子句。
=== 使用 find_by_sql 方法的 Active Record 查询接口
Lookup.find_by_sql("SELECT * FROM lookups LEFT OUTER JOIN through_tables ON (through_tables.lookup_id = lookups.id AND through_tables.through_reference_id = 1) LEFT OUTER JOIN through_references ON through_references.id = through_tables.through_reference_id ORDER BY lookups.value, through_references.id" )
从 Active Record 查询界面返回的内容(注意我在 Active Record 层次结构中向下导航)::
Lookup ID Lookup Name Lookup Value Through Table ID Through Table Description Main Item ID Main Item Description
1 Lookup Item 1 1 3 Main Item 2 has Lookup item 1 2 Main Item 2
1 Lookup Item 1 1 1 Main Item 1 has Lookup item 1 1 Main Item 1
Lookup Item 2 2 No through_tables entry
1 Lookup Item 3 3 3 Main Item 2 has Lookup item 1 2 Main Item 2
1 Lookup Item 3 3 1 Main Item 1 has Lookup item 1 1 Main Item 1
这里的结果很疯狂!
这是一个BUG,这是预期的效果,还是我错过了什么?
我希望有一种干净的方法可以做到这一点,而不必生成两个结果集,并通过代码将它们合并。