2017-01-21 4 views
1

J'ai le schéma suivant:Comment utiliser NOT IN et se joint à 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 

Je veux tous les groupes qui sont publics ou privés et non une partie d'un groupe d'annonces appelé « MyAds » en utilisant AciveRecord. J'ai réussi à obtenir la liste en utilisant la requête suivante, mais il semble moche et je suis sûr qu'il existe une meilleure façon de le faire. quelqu'un peut-il aider s'il vous plait?

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')") 

Répondre

2

La condition OR peuvent être combinés en une seule condition IN si vous passez « public » et « privé » dans un tableau. Et vous voudrez peut-être vérifier merge pour laisser Rails gérer les conditions de jointure. Voici une alternative possible:

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)