Arel、联接和 Rails 查询
Posted
技术标签:
【中文标题】Arel、联接和 Rails 查询【英文标题】:Arel, Joins and Rails Queries 【发布时间】:2011-07-01 15:47:04 【问题描述】:我最近被一个问题困住了一段时间,并找到了通往 Arel 的方法,这看起来应该允许我在查询中执行 OR。
作为起点,我需要将现有的 Rails 3 查询转换为 Arel,而这正是我遇到问题的地方。
以下范围和查询按我的预期工作。它为我提供了与特定用户的广告相关的请求。
#in the Request class
scope :responder, lambda |user| joins(:ad).where(:ads => :user_id => user )
Request.responder(303).to_sql
=> "SELECT \"requests\".* FROM \"requests\" INNER JOIN \"ads\" ON \"ads\".\"id\" = \"requests\".\"ad_id\" WHERE (\"ads\".\"user_id\" = 303)"
根据 Arel github 页面上的 doco 和 Railscast 215,我应该能够执行以下操作来使用 Arel 复制查询
requests = Request.arel_table
ads = Ad.arel_table
where(requests.join(ads).on(ads[:id].eq(requests[:ad_id])))
这会导致错误
TypeError: Cannot visit Arel::SelectManager
我可以在控制台中执行以下操作
r = Request.arel_table
a = Ad.arel_table
r.join(a).to_sql
=> "SELECT FROM \"requests\" INNER JOIN \"ads\" "
所以看起来它正在形成 SQL 请求,但是当你把它放在 where 中时
Request.where(r.join(a)).to_sql
我得到以下信息
TypeError: Cannot visit Arel::SelectManager....
我已经尝试在 where 内执行其他 Arel 操作并且它有效(例如)
Request.where(r[:status].eq(nil)).to_sql
=> "SELECT \"requests\".* FROM \"requests\" WHERE (\"requests\".\"status\" IS NULL)"
这有点超出了我不断增长的 rails/ruby 知识。有什么想法吗?
提前致谢。
【问题讨论】:
【参考方案1】:我不是 Arel 专家,但我认为您希望将 join 和 where 范围结合起来,而不是在另一个范围内包含一个。所以不是
where(requests.join(ads).on(ads[:id].eq(requests[:ad_id])))
尝试(例如):
requests.join(ads).on(ads[:id].eq(requests[:ad_id])).where(requests[:status].eq(nil))
【讨论】:
感谢 zetetic。我会试试看。 如果你在末尾添加一个“.to_sql”并将其放在Request.find_by_sql(...)
中,那就可以了【参考方案2】:
要在 rails 3 中执行 OR,请查看 MetaWhere。上面有一个不错的 railscast:http://railscasts.com/episodes/251-metawhere-metasearch
【讨论】:
感谢 DGM。我已经看过 MetaWhere,但我试图避免添加另一个 gem,因为它似乎已经在 rails 中有设施。不过我应该再看看。【参考方案3】:这里更大的答案是,尽管这里有花哨、鼓舞人心的例子: http://magicscalingsprinkles.wordpress.com/2010/01/28/why-i-wrote-arel/
...Active Record 实际上并不支持完整的 Arel 功能。至少,不是通过关系或范围。您可以在 Arel 中创建任何(大多数)查询,但最终您将使用:
sql = User.arel_table.(something awesome in Arel).to_sql
users = User.find_by_sql(sql)
从技术上讲,仍然有一个“.to_a”方法,但它不返回 ActiveRecord 模型实例,并且它已被弃用。
更新
http://erniemiller.org/projects/squeel/ 是 ActiveRecord 有史以来最好的事情。所有这些 Arel 的东西,都实现了。
【讨论】:
您的 wordpress 链接已失效 我知道!但这是 2011 年初的一个非常好的链接。我很遗憾他不再炫耀那个项目了。 archive.org 僵尸博客链接:web.archive.org/web/20110202025045/http://…【参考方案4】:到目前为止,我发现的最灵活的解决方案如下:
class Request
class << self
def your_join_scope
joins('INNER JOIN "ads" ON "ads"."id" = "requests"."ad_id"')
end
end
end
它的强大之处在于您可以将它与其他示波器混合搭配
【讨论】:
不需要使用 Arel::SqlLiteral 为什么不直接加入('INNER JOIN "ads" ON "ads"."id" = "requests"."ad_id"')【参考方案5】:您可以在Arel::SelectManager
上使用join_sources.first
并将其传递给加入
requests = Request.arel_table
ads = Ad.arel_table
Request.joins(requests.join(ads).on(ads[:id].eq(requests[:ad_id])).join_sources.first)
【讨论】:
你也可以只做join_sources
joins 会弄明白的。我相信如果你有多个但不要在第二部分引用我的话,这也会通过所有这些以上是关于Arel、联接和 Rails 查询的主要内容,如果未能解决你的问题,请参考以下文章