Arel、联接和 Rails 查询

发布于 2024-10-18 14:50:55 字数 1372 浏览 4 评论 0原文

我最近被一个问题困扰了一段时间,并找到了 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 请求,但是当你把它放在

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 知识。有什么想法吗?

提前致谢。

I've been stuck on a problem recently for a little while and found my way to Arel which looks like it should allow me to do OR's in my queries.

As a starting point I needed to convert an existing Rails 3 query to Arel and that's where I've run into problems.

The following scope and query works as I would expect it to. It gives me the requests associated with a particular user's ads.

#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)"

According to doco on the Arel github page and Railscast 215 I should be able to do something like the following to replicate the query with Arel

  requests = Request.arel_table
  ads = Ad.arel_table
  where(requests.join(ads).on(ads[:id].eq(requests[:ad_id])))

This results in an error

TypeError: Cannot visit Arel::SelectManager

I can do the following in the console though

r = Request.arel_table
a = Ad.arel_table

r.join(a).to_sql
 => "SELECT  FROM \"requests\" INNER JOIN \"ads\" "

So it looks like it's forming the SQL request, however when you put that in a where

Request.where(r.join(a)).to_sql

I get the following

TypeError: Cannot visit Arel::SelectManager....

I've tried doing other Arel actions within the where and it works (e.g.)

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

This is a little beyond my growing rails/ruby knowledge. Any ideas?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

回眸一笑 2024-10-25 14:50:55

您可以在 Arel::SelectManager 上使用 join_sources.first 并将其传递给 joins

requests = Request.arel_table
ads = Ad.arel_table
Request.joins(requests.join(ads).on(ads[:id].eq(requests[:ad_id])).join_sources.first)

You can use join_sources.first on Arel::SelectManager and the pass this to joins

requests = Request.arel_table
ads = Ad.arel_table
Request.joins(requests.join(ads).on(ads[:id].eq(requests[:ad_id])).join_sources.first)
筑梦 2024-10-25 14:50:55

这里更大的答案是,尽管这里有一个奇特的、鼓舞人心的例子:
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,永远。所有这些阿雷尔的事情,都意识到了。

The larger answer here, is that despite the fancy, inspiring example here:
http://magicscalingsprinkles.wordpress.com/2010/01/28/why-i-wrote-arel/

...Active Record doesn't actually support full Arel functionality. At least, not through relations or scopes. You can create any (most) queries in Arel, but in the end you're going to be using:

sql = User.arel_table.(something awesome in Arel).to_sql
users = User.find_by_sql(sql)

Technically, there's still a ".to_a" method, but it doesn't return ActiveRecord model instances, and it's deprecated.

{UPDATE}

http://erniemiller.org/projects/squeel/ is the best thing to happen to ActiveRecord, ever. All that Arel stuff, realized.

瑾夏年华 2024-10-25 14:50:55

我不是 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))

I'm no Arel expert, but I think you want to combine the join and where scopes instead of including one within the other. So instead of

where(requests.join(ads).on(ads[:id].eq(requests[:ad_id])))

try (for instance):

requests.join(ads).on(ads[:id].eq(requests[:ad_id])).where(requests[:status].eq(nil))
囍孤女 2024-10-25 14:50:55

要在 Rails 3 中进行 OR 运算,请查看 MetaWhere。上面有一个很好的railscast: http://railscasts.com/episodes/251-metawhere-metasearch< /a>

To do OR's in rails 3, check out MetaWhere. There's a nice railscast on it: http://railscasts.com/episodes/251-metawhere-metasearch

情魔剑神 2024-10-25 14:50:55

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

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

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

The most flexible solution I have found so far is something like the following:

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

The power of it is that you can mix and match it with your other scopes

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文