Chu*_*ckE 5 sql activerecord arel ruby-on-rails-3
我有这个用例,我从某个模型获得符号化的深层关联,我必须执行涉及使用外连接的某些查询.如何在不用手写完整SQL的情况下做到这一点?
答案我不想要: - 使用包括(不能很好地解决深层关联(.includes(:cars => [:windows,:engine => [:ignition] .....意外地工作)我不喜欢我不想要它的副作用 - 自己编写SQL(对不起,它是2013,跨数据库支持等等......,我获取的对象是read_only,更多的副作用)
我想要一个Arel解决方案.我知道使用模型中的arel_table我可以构造SQL表达式,还有一个用于连接的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!!
Run Code Online (Sandbox Code Playgroud)
为什么这不起作用超出了我的范围.我不知道到底缺少什么.但它与我现在的解决方案最接近.如果有人可以帮我完成我的例子,或者给我一个很好的解决方法,或者告诉我什么时候Rails包含这样一个明显必要的功能将会有我永远的感激之情.
我发现了一篇旨在解决这个问题的博客文章: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)
Run Code Online (Sandbox Code Playgroud)
这是一个老问题,但为了通过搜索引擎找到它的人的利益:
如果你想要传递的东西.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)
Run Code Online (Sandbox Code Playgroud)
要么
使用.join_sources构造的连接对象:
eng_exp = car.join(engine, Arel::Nodes::OuterJoin).on(car[:engine_id].eq(engine[:id]))
Car.joins(eng_exp.join_sources)
Run Code Online (Sandbox Code Playgroud)