我最近一直困在一个问题上并且找到了我去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页面和Railscast 215上的doco,我应该能够执行以下操作以使用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....
我已尝试在其中工作的其他Arel动作(例如)
Request.where(r[:status].eq(nil)).to_sql
=> "SELECT \"requests\".* FROM \"requests\" WHERE (\"requests\".\"status\" IS NULL)"
这有点超出了我不断增长的rails / ruby知识。有什么想法吗?
提前致谢。
答案 0 :(得分:9)
您可以在join_sources.first
上使用Arel::SelectManager
并将其传递给加入
requests = Request.arel_table
ads = Ad.arel_table
Request.joins(requests.join(ads).on(ads[:id].eq(requests[:ad_id])).join_sources.first)
答案 1 :(得分:8)
这里更大的答案是,尽管这里有一个奇特,鼓舞人心的例子: 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模型实例,和它已被弃用。
{UPDATE}
http://erniemiller.org/projects/squeel/是ActiveRecord发生的最好的事情。所有Arel的东西,实现了。
答案 2 :(得分:3)
我不是Arel专家,但我认为您希望将连接和范围组合在一起,而不是将其中一个包含在另一个范围内。而不是
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))
答案 3 :(得分:1)
要在rails 3中执行OR,请查看MetaWhere。有一个很好的轨道广播:http://railscasts.com/episodes/251-metawhere-metasearch
答案 4 :(得分:0)
到目前为止,我发现的最灵活的解决方案如下:
class Request
class << self
def your_join_scope
joins('INNER JOIN "ads" ON "ads"."id" = "requests"."ad_id"')
end
end
end
它的强大之处在于你可以将它与其他范围混合搭配