我有一个模型Edge属于另一个模型Node通过不同的外键两次:
def Edge < ActiveRecord::Base belongs_to :first,class_name: 'Node' belongs_to :second,class_name: 'Node' end
而且我想使用ActiveRecord来执行这个查询:
SELECT * FROM edges INNER JOIN nodes as first ON first.id = edges.first_id WHERE first.value = 5
Edge.joins(:first)
但是这样会产生使用表名称而不是关联名的查询,所以在.where()方法中,我必须明确地使用破坏关联抽象的表名.
Edge.joins(:first).where(nodes: {value: 5})
我也可以在.joins()方法中明确使用SQL查询来定义模型别名:
Edge.joins('INNER JOIN nodes as first ON nodes.id = edges.first_id')
但是,这样会更加抽象化.
我认为应该有一种方法来自动定义表的别名.或者也许是一种自己写这个功能的方法.就像是:
def Edge < ActiveRecord::Base ... def self.joins_alias # Generate something like # joins("INNER JOIN #{relation.table} as #{relation.alias} ON #{relation.alias}.#{relation.primary_key} = #{table}.#{relation.foreign_key}") end end
但是我没有找到有关访问有关特定关系的信息的信息,如名称,外键等.那么我该怎么办?
对于我来说,似乎也很奇怪,即使Rails已经在其第四个主要版本,这样的显着特征也是如此复杂.也许我错过了什么?
解决方法
对于Rails 4.2.1,我相信当使用ActiveRecord的连接时,您不能提供别名.
如果要通过第一个节点查询边缘,您可以像您所说的那样执行:
Edge.joins(:first).where(nodes: {value: 1}) SELECT "edges".* FROM "edges" INNER JOIN "nodes" ON "nodes"."id" = "edges"."first_id" WHERE "nodes"."value" = 1
但是如果您必须使用这两个节点进行查询,您仍然可以使用这样的连接:
Edge.joins(:first,:second).where(nodes: {value: 1},seconds_edges: {value: 2}) SELECT "edges".* FROM "edges" INNER JOIN "nodes" ON "nodes"."id" = "edges"."first_id" INNER JOIN "nodes" "seconds_edges" ON "seconds_edges"."id" = "edges"."second_id" WHERE "nodes"."value" = 1 AND "seconds_edges"."value" = 2