2017-10-21 139 views
2

我想写一个ActiveRecord查询,返回就读于一定的疗程用下面的查询所有学生:ActiveRecord的查询与多个联接不承认的关系

def self.students_enrolled_in(course_id) 
    Student 
     .joins(:enrollments) 
     .joins(:sections) 
     .joins(:courses) 
     .where(sections: { course_id: course_id }) 
    end 

结果在轨控制台:

ActiveRecord::ConfigurationError: Can't join 'Student' to association named 'sections'; perhaps you misspelled it?

它似乎是该协会是作出。我究竟做错了什么?这个查询实际上是否意味着所有的join()语句都必须与Student关联,或者应该找出关系链接?

教授展示页:

<div class="col-md-8"> 
    <h2 class="card-title"><%= @professor.name %></h2> 

    <% @courses_taught.each do |course| %> 
     <div class="card mb-4 card-header"> 
      <img class="card-img-top" src="http://placehold.it/750x300" alt="Card image cap"> 
      <h3 class="card-text"><%= course.title %></h3> 
     </div> 
     <div class="card-body"> 
      <% course.sections.enrollments.students.each do |student| %> 
       <p><% student.name %></p> 
      <% end %> 
     </div> 
    <% end %> 

</div> 

型号:

招生

class Enrollment < ApplicationRecord 
    belongs_to :section 
    belongs_to :student 
end 

学生:

class Student < ApplicationRecord 
    has_many :enrollments 
end 

教授:

class Section < ApplicationRecord 
    has_many :enrollments 
    belongs_to :professor 
    belongs_to :course 

    validates_uniqueness_of :professor_id, scope: :course_id 

    scope :by_professor_id, ->(prof_id) { where('professor_id = ?', prof_id) } 
end 

课程:

class Course < ApplicationRecord 
    enum status: { planning: 0, offered: 1 } 

    scope :offered, -> { where(status: 1) } 
    scope :planning, -> { where(status: 0) } 

    belongs_to :department 
    has_many :sections 
    has_many :professors, through: :sections 

    validates :title, :number, :status, :description, presence: true 
    validates :description, length: { in: 10..500 } 
    validates :title, :number, uniqueness: { case_sensitive: false } 

    def self.search(term) 
    if term 
     where('title LIKE ?', "%#{term}%").order('title DESC') 
    else 
     order('title ASC') 
    end 
    end 

    def self.taught_by(professor_id) 
    Course 
     .joins(:sections) 
     .joins(:professors) 
     .where(sections: { professor_id: professor_id }) 
     .select('distinct courses.*') 
    end 

end 

模式:

ActiveRecord::Schema.define(version: 20171013201907) do 

    create_table "courses", force: :cascade do |t| 
    t.string "title" 
    t.text "description" 
    t.string "number" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    t.integer "status", default: 0 
    t.integer "department_id" 
    t.index ["department_id"], name: "index_courses_on_department_id" 
    end 

    create_table "departments", force: :cascade do |t| 
    t.string "name" 
    t.text "description" 
    t.text "main_image" 
    t.text "thumb_image" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    end 

    create_table "enrollments", force: :cascade do |t| 
    t.integer "section_id" 
    t.integer "student_id" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    t.index ["section_id"], name: "index_enrollments_on_section_id" 
    t.index ["student_id"], name: "index_enrollments_on_student_id" 
    end 

    create_table "professors", force: :cascade do |t| 
    t.string "name" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    t.integer "status", default: 0 
    t.integer "department_id" 
    t.text "bio" 
    t.index ["department_id"], name: "index_professors_on_department_id" 
    end 

    create_table "sections", force: :cascade do |t| 
    t.integer "number" 
    t.integer "max_enrollment" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    t.integer "professor_id" 
    t.integer "course_id" 
    t.string "room" 
    t.index ["course_id"], name: "index_sections_on_course_id" 
    t.index ["professor_id", "course_id"], name: "index_sections_on_professor_id_and_course_id", unique: true 
    t.index ["professor_id"], name: "index_sections_on_professor_id" 
    end 

    create_table "students", force: :cascade do |t| 
    t.string "name" 
    t.decimal "gpa" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    end 

    create_table "users", force: :cascade do |t| 
    t.string "email", default: "", null: false 
    t.string "encrypted_password", default: "", null: false 
    t.string "name" 
    t.string "reset_password_token" 
    t.datetime "reset_password_sent_at" 
    t.datetime "remember_created_at" 
    t.integer "sign_in_count", default: 0, null: false 
    t.datetime "current_sign_in_at" 
    t.datetime "last_sign_in_at" 
    t.string "current_sign_in_ip" 
    t.string "last_sign_in_ip" 
    t.datetime "created_at", null: false 
    t.datetime "updated_at", null: false 
    t.string "roles" 
    t.index ["email"], name: "index_users_on_email", unique: true 
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true 
    end 

end 

回答

1

你过应用.joins。尝试从内到外尝试。首先,找到课程:

Course.find_by(id: course_id) 

然后,找到与course相关联的所有部分。不需要做这里joins

Section.where(course: Course.find_by(id: course_id)) 

现在,你做你的加入:

Student.joins(:enrollments).where(enrollments: {section: Section.where(course: Course.find_by(id: course_id))}) 

认为是应该做的伎俩为您服务。但是,未经测试。所以,给它一个去看看它是否有效。

P.S .:试试只发布最相关的代码。排除一堆无关的东西并不是很有趣。

+0

谢谢,我现在会测试它。并不完全确定这种情况下的相关性,如果知道这些实体之间的相关性是否恰当,那么它们就被包括在内。 – StillLearningToCode

0

朋友。

Student .joins(enrollments: [:sections,:courses]) .where(sections: { course_id: course_id })

Student .joins(enrollments: [:sections]) .where(sections: { course_id: course_id })

1

另一种方式做,这是一些协会添加到您的Student型号:

class Student < ApplicationRecord 
    has_many :enrollments 
    has_many :sections, through: :enrollments 
    has_many :courses, through: :sections 

    scope :enrolled_in_course, -> (course) { joins(:sections).where(course_id: course.id) 
end 

然后你可以找到所有学生在course招收有:

Student.enrolled_in_course(course) 
+0

这比接受的答案好得多。 – max