Users/Classroom 协会

Users/Classroom Associations

我是 rails 的新手,我正在尝试创建一个应用程序,用户可以在其中拥有很多教室,而教室可以有很多用户。但是,我不确定如何设置模型。

假设我有一位老师叫乔。乔有很多教室。 Joe 的每个教室都可以有很多学生,所以从这么多教室 Joe 也有很多学生。但我也希望 Joe 能够作为学生成为课堂的一部分,我希望学生能够从同一个帐户创建自己的课堂,作为老师。

教室也应该可以有不止一位老师。

我也希望能够做类似 user.classrooms.first.users 的事情,其中​​用户是 Joe,用户是他第一个教室里的学生。

我应该创建什么模型,我将如何设置关联?

我在想has_and_belongs_to_many,但显然它不再是首选,has_many :through会更好。它在我看来是这样的:

class User
  has_many :classroom_users
  has_many :classrooms, :through => :classroom_users
end

class Classroom
  has_many :classroom_users
  has_many :users, :through => :classroom_users
end

class Classroom_User
  belongs_to :classroom
  belongs_to :user
end

这是正确的吗?我从 here 拿来的。 另外,我应该如何通过迁移在数据库中镜像这些模型?

你现在所得到的将适用于将用户与教室相关联的情况,但不适用于教师,因为目前将两种模型相关联的 table 只能表示一种类型关系。

注意:Rails 期望模型名称是单数且没有下划线,即在您的示例中 ClassroomUser 而不是 Classroom_Users

要将教师与教室关联起来,一种方法是创建一个额外的连接模型:

user.rb:

class User < ActiveRecord::Base
  has_many :classroom_teachers
  has_many :classroom_students
  has_many :teaching_classrooms, through: :classroom_teachers
  has_many :attending_classrooms, through: :classroom_students
end

classroom.rb:

class Classroom < ActiveRecord::Base
  has_many :classroom_teachers
  has_many :classroom_students
  has_many :teachers, through: :classroom_teachers
  has_many :students, through: :classroom_students
end

classroom_student.rb:

class ClassroomStudent < ActiveRecord::Base
  belongs_to :student, class_name: 'User', foreign_key: 'user_id'
  belongs_to :attending_classroom, class_name: 'Classroom', foreign_key: 'classroom_id'
end

classroom_teacher.rb:

class ClassroomTeacher < ActiveRecord::Base
  belongs_to :teacher, class_name: 'User', foreign_key: 'user_id'
  belongs_to :teaching_classroom, class_name: 'Classroom', foreign_key: 'classroom_id'
end

Rails 通常根据字段名称计算出与字段相关的模型类型,例如users 字段将 link 到 User 个模型的集合。使用上述模式,Rails 无法从关联字段的名称推断模型的类型,因为它不知道 teacheruser 的别名.为了克服这个问题,class_name 属性定义了连接字段的模型类型。

出于同样的原因,Rails 需要一些指导来了解哪个数据库键与哪个字段相关,这就是 foreign_key 属性的用途。

最后是迁移:

class CreateClassroomUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
    end

    create_table :classrooms do |t|
    end

    create_table :classroom_students do |t|
      t.belongs_to :user, index: true
      t.belongs_to :classroom, index: true
    end

    create_table :classroom_teachers do |t|
      t.belongs_to :user, index: true
      t.belongs_to :classroom, index: true
    end
  end
end

编辑:

或者,您可以将一个额外的字段添加到您最初拥有的 ClassroomUser 模型,而不是使用两个连接模型,以描述用户的角色(例如,一个 enum 可以是studentteacher)。这将允许将来添加更多角色,并且可能比我之前的建议更容易查询。例如,要检查用户是学生还是老师,您只需要一个查询:

example_user.classroom_users

然后可以检查返回的 ClassroomUser 记录中的角色字段。有关该方法的示例,请参阅 this question