2016-04-09 3 views
1

Benutzer und Sitzungen sind durch eine has_and_belongs_to_many Assoziation verbunden.Wie schreibe ich eine ActiveRecord-Abfrage, die Ergebnisse aus einer Join-Tabelle herausfiltert?

Wie bekomme ich die eindeutige Liste der Benutzer, die die folgenden Bedingungen erfüllen?

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

Und dann sind NICHT ein Benutzer, wenn dieser Benutzer ein Trainer in einer aktiven Session ist:

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

Gibt es eine Möglichkeit, dies mit ActiveRecord Query Sprache schreiben? Muss ich eine reine SQL-Anweisung schreiben? Irgendeine Art von Hybrid? Was würden Sie tun?

Ich habe auch Bereiche definiert, die hier hilfreich sein könnten. Aber ich bin nicht sicher, wie sie in hinzuzufügen:

  • User.available_coaches (scope)
  • Session.in_progress (scope)

User-Modell

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 Modell

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) } 

Schema

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 (: Sitzungen) .where (Trainer: true, verfügbar: true) .where.not (Sitzungen: {coach_id: user.id, call_ends_at: nil})' - überprüfen Sie, ob dies für Sie funktioniert, Ich habe es nicht getestet. – dp7

+0

Danke !! Es war sehr nah und half mir, es zu lösen. 'User.joins (: coach_sessions) .where (Trainer: true, available: true) .where.not (Sitzungen: {call_ends_at: nil}). Uniq' –

+0

Hmm ... Eigentlich ist das nicht so. Ich muss die Benutzer finden, die keine Sitzungen haben, die "call_ends_at: nil". Dies gibt Benutzer mit Sitzungen zurück, bei denen 'call_ends_at' auf nicht null gesetzt ist. Ist das sinnvoll? –

Antwort

1

ich es mit SQL tun würde 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)") 

Beachten Sie, dass, da es keine zu sessions beitreten gibt es keine Notwendigkeit für .uniq ist.

Verwandte Themen