如何通过Rails ActiveRecord中的连接正确别名has_many?

use*_*094 2 ruby activerecord ruby-on-rails

Rails/ActiveRecord新手在这里.考虑以下用于课堂,用户和课堂注册的模型(两者之间的连接)

class Classroom < ActiveRecord::Base
  has_many :fulltime_enrollments, -> { where(duration: 'full-time') }, class_name: "ClassroomEnrollments"
  has_many :fulltimers, :through => :fulltime_enrollments, class_name: "User"

  has_many :parttime_enrollments, -> { where(duration: 'part-time') }, class_name: "ClassroomEnrollments"
  has_many :parttimers, :through => :parttime_enrollments, class_name: "User"
end

class ClassroomEnrollment < ActiveRecord::Base
  # columns: user_id, classroom_id, duration
  belongs_to :user
  belongs_to :classroom
end

class User < ActiveRecord::Base
  has_many :classroom_enrollments
  has_many :classrooms, :through => :classroom_enrollments
end
Run Code Online (Sandbox Code Playgroud)

教室和课堂教程的以下模型不起作用.当我尝试通过或访问它们时,特别是:fulltimers:parttimers别名抛出undefined method 'to_sym' for nil:NilClass错误.my_classroom.fulltimersmy_classroom.parttimers

如果我删除:parttimers别名并重命名:fulltimers:users它工作正常(并且只显示全职学生),所以在我看来,它与它有关,弄清楚它:fulltimers是类型User,即使我已经指定classname: "User"has_many条件.

我究竟做错了什么?

Jor*_*lan 5

由于无法自动推断源关联,因此您需要使用以下:source选项指定它:

class Classroom < ActiveRecord::Base
  has_many(
    :fulltime_enrollments, 
    -> { where(duration: 'full-time') }, 
    class_name: "ClassroomEnrollments"
  )
  has_many :fulltimers, :through => :fulltime_enrollments, :source => :user

  has_many(
    :parttime_enrollments, 
    -> { where(duration: 'part-time') }, 
    class_name: "ClassroomEnrollments"
  )
  has_many :parttimers, :through => :parttime_enrollments, :source => :user
end
Run Code Online (Sandbox Code Playgroud)

http://guides.rubyonrails.org/association_basics.html#options-for-has-many-source

尝试更清晰,更易读的方法怎么样?像这样的东西:

class Classroom < ActiveRecord::Base
  has_many :classroom_enrollments
  has_many :users, through: :classroom_enrollments

  def full_timers
    users_by_duration("full-time")
  end

  def part_timers
    users_by_duration("part-time")
  end

  private

  def users_by_duration(duration)
    users.where(classroom_enrollments: { duration: duration })
  end
end
Run Code Online (Sandbox Code Playgroud)

然后:

my_classroom = Classroom.find(1)
my_classroom.full_timers
Run Code Online (Sandbox Code Playgroud)