我有这个用例,我从某个模型获得符号化的深层关联,我必须执行某些涉及使用外连接的查询。如何在不用手写完整SQL的情况下做到这一点?
答案我不想要: - 使用包括(不能很好地解决深层关联(.includes(:cars => [:windows,:engine => [:ignition] .....意外工作)我不想要它的一面效果 - ) - 自己编写SQL(抱歉,它是2013,跨数据库支持等等......,我获取的对象是read_only,更多的副作用)
我想要一个Arel解决方案。我知道使用我可以构建SQL表达式的模型中的arel_table,还有一个用于连接的DSL,但不知怎的,我不能在模型的连接方法中使用它:
car = Car.arel_table
engine = Engine.arel_table
eng_exp = car.join(engine).on(car[:engine_id].eq(engine[:id]))
eng_exp.to_sql #=> GOOD! very nice!
Car.joins(eng_exp) #=> Breaks!!
为什么这不起作用超出了我的范围。我不知道到底缺少什么。但它与我现在的解决方案最接近。如果有人可以帮我完成我的例子,或者给我一个很好的解决方法,或者告诉我什么时候Rails包含这样一个明显必要的功能将会有我永远的感激之情。
答案 0 :(得分:7)
我发现了一篇旨在解决此问题的博文:http://blog.donwilson.net/2011/11/constructing-a-less-than-simple-query-with-rails-and-arel/
基于此(以及我自己的测试),以下内容适用于您的情况:
car = Car.arel_table
engine = Engine.arel_table
sql = car.project(car[Arel.star])
.join(engine, Arel::Nodes::OuterJoin).on(car[:engine_id].eq(engine[:id]))
Car.find_by_sql(sql)
答案 1 :(得分:6)
这是一个老问题,但是为了通过搜索引擎找到它的人的利益:
如果您想要传递给.joins
的内容,可以使用.create_join
和.create_on
:
join_on = car.create_on(car[:engine_id].eq(engine[:id]))
eng_join = car.create_join(engine, join_on, Arel::Nodes::OuterJoin)
Car.joins(eng_join)
OR
使用构建的连接对象中的.join_sources
:
eng_exp = car.join(engine, Arel::Nodes::OuterJoin).on(car[:engine_id].eq(engine[:id]))
Car.joins(eng_exp.join_sources)
答案 2 :(得分:0)
如果您不介意添加依赖项并完全跳过AREL,则可以使用Ernie Miller's excellent Squeel gem。这就像是
Car.joins{engine.outer}.where(...)
这将要求Car模型与Engine关联,如下所示:
belongs_to :engine