由于您没有展示您的模型,我将做出一些假设。在以下模型中,我将仅包含必需的属性。当然,你会拥有更多(例如,Course 可能会有 name,CourseSession 可能会有 time,等等)。
在这一切结束后,您将能够通过执行以下操作让所有学生注册到给定学期:
User.enrolled_for_term(term)
您将能够通过以下方式获得所有未注册给定学期的学生:
User.not_enrolled_for_term(term)
首先,我们假设:
- 您有一个
Term 模型(例如“2019 年秋季”或“2019 年冬季”)
- 您有一个
Course 模型(例如“Bio 100”或“Chem 100”)
- 一个
Term 可以有多个Courses(“2019 年秋季”可能会提供“Bio 100”和“Chem 100”)
-
Course 可以在许多Terms 中提供(“Bio 100”可能在“2019 年秋季”和“2019 年冬季”提供)
- 您有一个
CourseTerm 模型,它允许Terms 和Courses 之间的多对多关系
Term 可能看起来像:
# == Schema Information
#
# Table name: terms
#
# id :bigint not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
#
class Term < ApplicationRecord
has_many :course_terms
has_many :courses, through: :course_terms
end
Course 可能看起来像:
# == Schema Information
#
# Table name: courses
#
# id :bigint not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
#
class Course < ApplicationRecord
has_many :course_terms
has_many :terms, through: :course_terms
end
CourseTerm 可能看起来像:
# == Schema Information
#
# Table name: course_terms
#
# id :bigint not null, primary key
# course_id :bigint
# term_id :bigint
# created_at :datetime not null
# updated_at :datetime not null
#
class CourseTerm < ApplicationRecord
belongs_to :course
belongs_to :term
class << self
def for_term(term)
where(term: term)
end
end
end
请注意,您可以使用CourseTerm.for_term(term) 获取Term 的所有CourseTerms。
现在,我们假设 Course 可以在 Term 期间多次取消(例如,课程可能在上午 9:00 和上午 10:00 提供)。我认为这就是您所说的“会话”。我们称之为CourseSession,它可能看起来像:
# == Schema Information
#
# Table name: course_sessions
#
# id :bigint not null, primary key
# course_term_id :bigint
# created_at :datetime not null
# updated_at :datetime not null
#
class CourseSession < ApplicationRecord
belongs_to :course_term
class << self
def for_term(term)
where(course_term: CourseTerm.for_term(term))
end
end
end
请注意,您可以使用CourseSession.for_term(term) 获取Term 的所有CourseSessions。
现在,让我们假设 User 可以与 CourseSession 相关联,这就是我假设您所说的“注册”的意思。我称之为StudentCourseSession:
# == Schema Information
#
# Table name: student_course_sessions
#
# id :bigint not null, primary key
# student_id :integer
# course_session_id :bigint
# created_at :datetime not null
# updated_at :datetime not null
#
class StudentCourseSession < ApplicationRecord
belongs_to :course_session
belongs_to :student, class_name: "User"
class << self
def for_course_sessions(course_sessions)
where(course_session: course_sessions)
end
def for_term(term)
for_course_sessions(CourseSession.for_term(term))
end
end
end
请注意,您可以通过 StudentCourseSession.for_term(term) 获取“学期”的所有注册。
现在,在“用户”模型中,添加 has_many :student_course_sessions 关联,指定 foreign_key: :student_id。您添加了一个enrolled_for_term(term) 方法,用于查找在指定学期注册的所有学生。然后,not_enrolled_for_term(term) 就变成了查找在指定学期注册的.not 的学生。
# == Schema Information
#
# Table name: users
#
# id :bigint not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
#
class User < ApplicationRecord
has_many :student_course_sessions, foreign_key: :student_id
class << self
def not_enrolled_for_term(term)
where.not(id: enrolled_for_term(term)).distinct
end
def enrolled_for_term(term)
joins(:student_course_sessions).
where(student_course_sessions: {id: StudentCourseSession.for_term(term)}).
distinct
end
end
end
这是对上述内容的 rspec 测试:
require 'rails_helper'
RSpec.describe "Unenrolled Students" do
before(:each) do
create(:student_course_session, student: user_1, course_session: course_session_1)
create(:student_course_session, student: user_2, course_session: course_session_2)
create(:student_course_session, student: user_2, course_session: course_session_3)
end
it "works" do
expect(User.enrolled_for_term(term_1)).to include(user_1)
expect(User.enrolled_for_term(term_1)).to include(user_2)
expect(User.enrolled_for_term(term_1)).not_to include(user_3)
expect(User.not_enrolled_for_term(term_1)).not_to include(user_1)
expect(User.not_enrolled_for_term(term_1)).not_to include(user_2)
expect(User.not_enrolled_for_term(term_1)).to include(user_3)
end
end
def user_1
@user_1 ||= create(:user)
end
def user_2
@user_2 ||= create(:user)
end
def user_3
@user_3 ||= create(:user)
end
def term_1
@term_1 ||= create(:term)
end
def course_1
@course_1 ||= create(:course)
end
def course_2
@course_2 ||= create(:course)
end
def course_term_1
@course_term_1 ||= create(:course_term, course: course_1, term: term_1)
end
def course_term_2
@course_term_2 ||= create(:course_term, course: course_1, term: term_1)
end
def course_term_3
@course_term_3 ||= create(:course_term, course: course_2, term: term_1)
end
def course_session_1
@course_session_1 ||= create(:course_session, course_term: course_term_1)
end
def course_session_2
@course_session_2 ||= create(:course_session, course_term: course_term_2)
end
def course_session_3
@course_session_3 ||= create(:course_session, course_term: course_term_3)
end
def student_course_session_1
@student_course_session_1 ||= create(:student_course_session, student: user_1, course_session: course_session_1)
end
这给出了:
10:55:58 - INFO - Running: spec/so/unenrolled_students_spec.rb
Unenrolled Students
works
Finished in 0.27546 seconds (files took 1.04 seconds to load)
1 example, 0 failures