2016-04-09 2 views
1

Пользователи и сеансы соединены ассоциацией has_and_belongs_to_many.Как написать запрос ActiveRecord, который отфильтровывает результаты из объединенной таблицы?

Как получить уникальный список пользователей, соответствующих следующим условиям?

  • user.coach == true
  • user.available == true

И тогда не включают пользователя, если этот пользователь является тренером в любой активной сессии:

  • session.coach_id == user.id
  • session.call_ends_at == nil

Есть ли способ написать это с помощью языка запросов ActiveRecord? Нужно ли писать чистую инструкцию SQL? Какой-то гибрид? Что бы вы сделали?

У меня также есть определенные области, которые могут быть полезны здесь. Но я не уверен, как добавить их в:

  • User.available_coaches (сфера)
  • Session.in_progress (сфера)

модель пользователя

class User < ActiveRecord::Base 
    has_many :client_sessions, class_name: 'Session', foreign_key: :client_id 
    has_many :coach_sessions, class_name: 'Session', foreign_key: :coach_id 

    scope :coaches, -> { where(coach: true) } 
    scope :available_coaches, -> { coaches.where(available: true) } 

модель Session

class Session < ActiveRecord::Base 
    belongs_to :client, class_name: 'User' 
    belongs_to :coach, class_name: 'User' 

    scope :in_progress, -> { where.not(coach: nil).where(call_ends_at: nil) } 

Схема

create_table "sessions", force: :cascade do |t| 
    t.integer "client_id" 
    t.integer "coach_id" 
    t.boolean "canceled",   default: false 
    t.datetime "coach_accepted_at" 
    t.datetime "call_begins_at" 
    t.datetime "call_ends_at" 
    t.datetime "created_at",      null: false 
    t.datetime "updated_at",      null: false 
end 

add_index "sessions", ["client_id"], name: "index_sessions_on_client_id", using: :btree 
add_index "sessions", ["coach_id"], name: "index_sessions_on_coach_id", using: :btree 

create_table "users", force: :cascade do |t| 
    t.string "first_name" 
    t.string "last_name" 
    t.boolean "coach",    default: false 
    t.boolean "available",   default: false 
    t.datetime "created_at",      null: false 
    t.datetime "updated_at",      null: false 
end 
+1

'User.joins (: sessions) .where (coach: true, available: true) .where.not (sessions: {coach_id: user.id, call_ends_at: nil})' - проверьте, работает ли это для вас, Я не тестировал его. – dp7

+0

Спасибо! Это было очень близко и помогло мне это решить. 'User.joins (: coach_sessions) .where (coach: true, available: true) .where.not (сеансы: {call_ends_at: nil}). Uniq' –

+0

Хм ... Собственно, этого не происходит. Мне нужно найти пользователей, у которых нет сеансов, которые 'call_ends_at: nil'. Это возвращает пользователей, у которых есть сеансы, у которых любой параметр 'call_ends_at' установлен равным нулю. Имеет ли это смысл? –

ответ

1

Я хотел бы сделать это с SQL exists:

User.where(coach: true, available: true). 
    where("not exists (select 1 from sessions " + 
    "where sessions.coach_id = users.id and sessions.call_ends_at is null)") 

Обратите внимание, что поскольку нет присоединиться к sessions нет необходимости .uniq.

Смежные вопросы