2017-01-21 2 views
1

У меня есть следующая схема:Как использовать NOT IN и присоединяться в AciveRecord/Rails 5?

create_table "ad_groups", force: :cascade do |t| 
    t.string "name" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
end 
create_table "ad_placements", force: :cascade do |t| 
    t.integer "advertisement_id" 
    t.integer "ad_group_id" 
    t.datetime "created_at",  null: false 
    t.datetime "updated_at",  null: false 
    t.index ["ad_group_id"], name: "index_ad_placements_on_ad_group_id", using: :btree 
    t.index ["advertisement_id"], name: "index_ad_placements_on_advertisement_id", using: :btree 
end 
create_table "advertisements", force: :cascade do |t| 
    t.string "name" 
    t.string "image" 
    t.string "link" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    t.date  "expiry_date" 
    t.integer "company_id" 
    t.index ["company_id"], name: "index_advertisements_on_company_id", using: :btree 
end 
create_table "companies", force: :cascade do |t| 
    t.string "name" 
    t.datetime "created_at",  null: false 
    t.datetime "updated_at",  null: false 

end 
create_table "groups", force: :cascade do |t| 
    t.string "name" 
    t.integer "company_id" 
    t.string "group_type" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.index ["company_id"], name: "index_groups_on_company_id", using: :btree 
end 

Я хочу, чтобы все группы, которые являются государственными или частными и не являются частью определенной группы объявлений называется «MyAds» с помощью AciveRecord. Мне удалось получить список, используя следующий запрос, но он выглядит уродливым, и я уверен, что есть лучший способ сделать это. Кто-нибудь может помочь?

Group.where("group_type = 'Public'").or(Group.where("group_type = 'Private'")).where("groups.id NOT IN (SELECT groups.id FROM advertisements INNER JOIN ad_placements ON advertisements.id = ad_placements.advertisement_id INNER JOIN ad_groups ON ad_placements.ad_group_id = ad_groups.id INNER JOIN groups on groups.company_id = advertisements.company_id WHERE ad_groups.name = 'MyAds')") 

ответ

2

OR условия может быть объединен в единый IN условия, если вы передадите «Public» и «Private» в массиве. И вы можете проверить merge, чтобы позволить Rails управлять условиями соединения. Вот возможная альтернатива:

my_ad_groups = Group.joins(company: { advertisements: { ad_placements: :ad_group } }).merge(AdGroup.where(name: 'MyAds')) 
Group.where(group_type: ['Public', 'Private']).where.not(id: my_ad_groups)