16

我最近被一个问题困住了一段时间,并找到了通往 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....

我已经尝试在 where 中执行其他 Arel 操作并且它有效(例如)

Request.where(r[:status].eq(nil)).to_sql
 => "SELECT \"requests\".* FROM \"requests\" WHERE (\"requests\".\"status\" IS NULL)"

这有点超出了我不断增长的 rails/ruby 知识。有任何想法吗?

提前致谢。

4

5 回答 5

9

您可以使用join_sources.firstonArel::SelectManager并将其传递给 join

requests = Request.arel_table
ads = Ad.arel_table
Request.joins(requests.join(ads).on(ads[:id].eq(requests[:ad_id])).join_sources.first)
于 2012-06-01T11:16:25.497 回答
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 模型实例,并且已被弃用。

{更新}

http://erniemiller.org/projects/squeel/是 ActiveRecord 有史以来最好的事情。所有Arel的东西,都意识到了。

于 2011-03-17T21:06:27.273 回答
3

我不是 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))
于 2011-02-22T04:00:22.257 回答
1

要在 rails 3 中执行 OR,请查看 MetaWhere。上面有一个不错的 railscast:http ://railscasts.com/episodes/251-metawhere-metasearch

于 2011-02-22T04:45:45.967 回答
0

到目前为止,我发现的最灵活的解决方案如下:

class Request
  class << self
    def your_join_scope
      joins('INNER JOIN "ads" ON "ads"."id" = "requests"."ad_id"')
    end
  end
end

它的强大之处在于您可以将它与其他示波器混合搭配

于 2011-07-18T14:01:05.737 回答