2016-05-28 4 views
3

Как я могу получить (A || B) & & (C || D) запрос в Rails 5 ActiveRecord ?. Я попытался Post.where(a).or(Post.where(b)).where(c).or(Post.where(d))OR статья в Rails 5

, но он производит, как: (А || Б) & & С || D. Каким будет правильный код для получения желаемого запроса?

+0

Вы нашли решение, которое вы хотели? –

ответ

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 
0

Вы пробовали толкая каждый из 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