【问题标题】:OR clause in Rails 5Rails 5 中的 OR 子句
【发布时间】:2016-05-28 13:29:44
【问题描述】:

如何在 Rails 5 ActiveRecord 中获取 (A || B) && ( C || D) 查询?我试过 Post.where(a).or(Post.where(b)).where(c).or(Post.where(d))

但它产生为:(A || B) && C || D。获得所需查询的正确代码是什么?

【问题讨论】:

  • 您找到想要的解决方案了吗?

标签: ruby-on-rails activerecord ruby-on-rails-5


【解决方案1】:

Rails or() 方法没有这个复杂。首次提出时,关于该功能的讨论很长here, on Github

此方法旨在提供一种便捷的 Railsifying 查询方式,但有时事情并没有那么简单。 or() 方法本质上是从左到右读取。

在坚持“Railsy”约定时,您最好的选择是遵循以下方法之一:

Post.where("a OR b").where("c OR d")             # Example 1 - SQL with additional where()
Post.where(a: [true, !b]).where(c: [true, !d])   # Example 2 - Array comparison
Post.where("(a OR b) AND (c OR d)")              # Example 3 - SQL only

【讨论】:

    【解决方案2】:

    您是否尝试过将每个or 查询下推到Post 模型中的各个命名范围?对我来说,将它们分开会产生不同的结果。试试下面的代码,看看你是否得到了预期的结果(我手边没有 Rails 应用程序,所以我把所有东西都放在一个 Ruby 文件中):

    rails_where_or.rb

    require 'active_record'
    require 'rspec'
    
    ActiveRecord::Base.establish_connection(
      adapter: 'sqlite3', database: ':memory:'
    )
    
    ActiveRecord::Schema.define do
      create_table :posts do |t|
        t.boolean :a, default: false
        t.boolean :b, default: false
        t.boolean :c, default: false
        t.boolean :d, default: false
      end
    end
    
    class Post < ActiveRecord::Base
      def self.a_or_b_and_c_or_d
        a_or_b.c_or_d
      end
    
      def self.a_or_b_and_c_or_d_all_chained
        where(a: true).or(where(b: true)).
          where(c: true).or(where(d: true))
      end
    
      def self.a_or_b
        where(a: true).or(where(b: true))
      end
    
      def self.c_or_d
        where(c: true).or(where(d: true))
      end
    end
    
    RSpec.describe Post do
      let!(:only_a) do
        described_class.create!(a: true)
      end
      let!(:only_b) do
        described_class.create!(b: true)
      end
      let!(:only_c) do
        described_class.create!(c: true)
      end
      let!(:only_d) do
        described_class.create!(d: true)
      end
      let!(:a_and_b) do
        described_class.create!(a: true, b: true)
      end
      let!(:a_and_c) do
        described_class.create!(a: true, c: true)
      end
      let!(:a_and_d) do
        described_class.create!(a: true, d: true)
      end
      let!(:b_and_c) do
        described_class.create!(b: true, c: true)
      end
      let!(:b_and_d) do
        described_class.create!(b: true, d: true)
      end
      let!(:c_and_d) do
        described_class.create!(c: true, d: true)
      end
    
      describe '.a_or_b_and_c_or_d' do
        let(:a_or_b_and_c_or_d) do
          described_class.a_or_b_and_c_or_d
        end
    
        it 'returns only records that match (A || B) && ( C || D )' do
          expect(a_or_b_and_c_or_d).not_to include(only_a)
          expect(a_or_b_and_c_or_d).not_to include(only_b)
          expect(a_or_b_and_c_or_d).not_to include(only_c)
          expect(a_or_b_and_c_or_d).not_to include(only_d)
          expect(a_or_b_and_c_or_d).not_to include(a_and_b)
          expect(a_or_b_and_c_or_d).not_to include(c_and_d)
          expect(a_or_b_and_c_or_d).to include(a_and_c)
          expect(a_or_b_and_c_or_d).to include(a_and_d)
          expect(a_or_b_and_c_or_d).to include(b_and_c)
          expect(a_or_b_and_c_or_d).to include(b_and_d)
        end
      end
    
      describe '.a_or_b_and_c_or_d_all_chained' do
        let(:a_or_b_and_c_or_d_all_chained) do
          described_class.a_or_b_and_c_or_d_all_chained
        end
    
        it 'returns records that match (A || B) && C || D ' do
          expect(a_or_b_and_c_or_d_all_chained).not_to include(only_a)
          expect(a_or_b_and_c_or_d_all_chained).not_to include(only_b)
          expect(a_or_b_and_c_or_d_all_chained).not_to include(only_c)
          expect(a_or_b_and_c_or_d_all_chained).not_to include(a_and_b)
          expect(a_or_b_and_c_or_d_all_chained).to include(only_d)
          expect(a_or_b_and_c_or_d_all_chained).to include(c_and_d)
          expect(a_or_b_and_c_or_d_all_chained).to include(a_and_c)
          expect(a_or_b_and_c_or_d_all_chained).to include(a_and_d)
          expect(a_or_b_and_c_or_d_all_chained).to include(b_and_c)
          expect(a_or_b_and_c_or_d_all_chained).to include(b_and_d)
        end
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-06
      • 1970-01-01
      • 2015-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多