【问题标题】:Rails: OR where condition on associationRails:或关联条件
【发布时间】:2016-04-15 13:06:31
【问题描述】:

我有一个名为Facility 的模型。它has_many :addressesAddress 型号 has_one :city

现在我想运行一个条件:

  • 获取所有没有关联地址的设施;
  • 如果他们有地址,请检查他们是否没有与该地址关联的城市模型。

我已经尝试了第一个条件,但我无法为它组合 OR。

这将获取所有没有关联地址模型的设施

Facility.includes(:addresses).where( :addresses => {:facility_id => nil})

一些错误尝试是:

Facility.includes(:addresses).where( :addresses => ({:facility_id => nil}).or({:city_id => nil}) );
Facility.includes(:addresses).where( :addresses => ({:facility_id => nil}).or(:address => {:city_id => nil}) )

【问题讨论】:

  • 你试过.or({:addresses => {:city_id => nil}}) );吗?
  • 是的,我做了,不起作用我做了一个编辑,检查是否是你所说的,错误是 NoMethodError: undefined method `or' for {:facility_id=>nil} :哈希
  • @coderVishal,你可能对使用 Squeel 感兴趣。对于 OR 条件和其他匹配器,例如 ,Squeel 使代码干净,而不是使用对错误敏感的 SQL 字符串。

标签: ruby-on-rails ruby-on-rails-4 activerecord rails-activerecord ruby-on-rails-4.2


【解决方案1】:

试试这个

Facility.includes(addresses: :city).where("addresses.facility_id IS NULL OR addresses.city_id IS NULL");

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    尝试以下方法:

    Facility.includes(:addresses)
            .where('addresses.facility_id is null or addresses.city_id is null')
            .references(:addresses)
    

    您还可以找到有趣的this post,关于在活动记录查询中or 条件的可能实现。

    【讨论】:

    • 谢谢这工作,我可以知道添加引用的目的,因为没有它我得到一个错误。
    • 这是必要的,因为where子句中有sql而不是hash guides.rubyonrails.org/…
    • @coderVishal:您从另一个表addresses 中检查where 子句中的列,因此从4.2 开始您应该明确地reference 它们。
    • @potashin 非常感谢。又省了一天。我想学习这个相关的东西,你能给我一个好的方向吗(一些教程或链接)
    • @coderVishal:好吧,官方文档是pretty explicit on the issue and related stuff
    【解决方案3】:

    首先,当你想对关联做条件时使用includes可能会产生负面影响:

    • 您将急切地加载数据,如果不需要,这意味着白做更多的工作
    • 急切加载的addresses 仅是匹配条件的那些。因此,如果您使用addresses,则不会获得该记录的所有记录(只有符合条件的记录)。这会导致奇怪的错误或难以理解的工作代码。

    为避免此问题和所有其他问题,我建议使用我专门为此制作的 gem:activerecord_where_assoc

    您的问题可以简化,我会在回复您的要求后简化:

    根据标签,您似乎正在使用 Rails 4.2。所以你还不能访问#or 方法。所以你可以这样做:

    sql_no_address = Facility.assoc_not_exists_sql(:addresses)
    sql_no_city = Facility.assoc_exists_sql(:addresses) { where_assoc_not_exists(:city) }
    Facility.where("#{sql_no_address} OR #{sql_no_city}")
    

    如果您有 Rails 5 或更高版本:

    Facility.where_assoc_not_exists(:addresses).or(Facility.where_assoc_not_exists([:addresses, :city]))
    

    现在,一个更简单的解决方案。请注意,如果设施没有地址,则它不能有城市,因为它必须通过地址才能到达城市。真的,你的问题只是“我想要没有城市的设施”。这就是将数组传递给方法所做的事情,它会尝试从一个到另一个直到结束。

    Facility.where_assoc_not_exists([:addresses, :city])
    

    这里是introductionexamples。在documentation 中阅读更多详细信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-26
      • 1970-01-01
      • 1970-01-01
      • 2018-01-24
      • 2011-03-26
      • 2015-12-15
      • 1970-01-01
      相关资源
      最近更新 更多