【问题标题】:activerecord joins multiple time the same tableactiverecord 多次连接同一个表
【发布时间】:2019-10-25 13:54:07
【问题描述】:

我正在做一个看起来像这样的简单搜索(有 8 个不同的参数,但我将复制 2 个作为示例)

 if params[:old] == "on"
   @events = @events.joins(:services).where(services: { name: "old" })
 end

 if params[:big] == "on"
   @events = @events.joins(:services).where(services: { name: "big" })
 end

当我只有一个“开启”参数并返回在参数中包含服务的事件时,查询工作正常。

但是,如果我有两个“开启”参数,即使我的事件有这两种服务,它也不再起作用了。

我已经在控制台中对其进行了测试,我可以看到如果我对之前已经加入的元素执行 .joins(:services).where(services: { name: "big" }) ,它什么都不返回。

我不明白为什么。

第一个@events(当一个参数时)返回一个包含一些事件的活动记录关系。

为什么我不能对其进行另一个 .joins 操作?

我真的不明白这个查询有什么问题,为什么它一加入两次就变成空的。

非常感谢

【问题讨论】:

  • 原因是因为你的where链接会在Sql查询中生成AND子句,比如WHERE services.name = "old" AND services.name = "big",这个在你的数据库中是不存在的。
  • 我认为您的意图是使用OR 而不是AND,对吗?
  • 嗯,我想我确实想要一个 AND。如果我只有一个参数,比如说“大”,我希望所有事件都具有“大”作为服务。但是一个事件可以有很多服务。因此,如果用户放置两个参数,“大”和“旧”,我希望所有事件都具有“大”和“旧”作为服务......当我在控制台中查看时确实存在
  • 如果我确实想要一个 AND 并且如果我有一个包含两种服务的事件,它应该可以工作吗?我错过了什么?
  • 不,这行不通。因为您的两个服务共享相同的名称变量。您将同时执行“name == big”和“name == old”,但它们不能同时相等。

标签: ruby-on-rails activerecord parameters active-record-query


【解决方案1】:

您使用的代码将转换为:

SELECT  "events".* FROM "events" INNER JOIN "services" ON "services"."event_id" = "events"."id" WHERE "services"."name" = ? AND "services"."name" = ? LIMIT ?  [["name", "big"], ["name", "old"], ["LIMIT", 11]]

这就是它返回零记录的原因。

这是我目前能想到的解决方案,不确定它是否是理想的,但可以,并且已经过测试。

# event.rb
class Event < ApplicationRecord
  has_many :services
  has_many :old_services, -> { where(name: 'old') }, class_name: 'Service'
  has_many :big_services, -> { where(name: 'big') }, class_name: 'Service'
end


# service.rb
class Service < ApplicationRecord
  belongs_to :event
end

而你的搜索方法可以这样写:

if params[:old] == "on"
  @events = @events.joins(:old_services)
end

if params[:big] == "on"
  @events = @events.joins(:big_services)
end

@events = @events.distinct
# SELECT  DISTINCT "events".* FROM "events" INNER JOIN "services" ON "services"."event_id" = "events"."id" AND "services"."name" = ? INNER JOIN "services" "old_services_events" ON "old_services_events"."event_id" = "events"."id" AND "old_services_events"."name" = ? LIMIT ?  [["name", "big"], ["name", "old"], ["LIMIT", 11]]

【讨论】:

  • 聪明!非常感谢。昨天我找到了另一个解决方案,即迭代我的所有事件,对每个事件执行 .pluck(:services),并检查我在循环中最终得到的数组是否与我拥有的相同在我的参数中。如果是,我将此事件推送到一个新数组中。这真的很不雅(实际上很糟糕,但我想不出别的)。我认为您的解决方案更好,更清洁!我试试看
  • 工作就像一个魅力,甚至帮助我重构我的代码并循环遍历所有 services_params :) 谢谢
  • 很高兴听到这个消息。
猜你喜欢
  • 1970-01-01
  • 2020-03-22
  • 2012-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-15
  • 1970-01-01
相关资源
最近更新 更多