2017-10-21 52 views
2

Je suis en train d'écrire un ActiveRecord requête qui retourne tous les étudiants inscrits à un certain cours avec la requête suivante:requête ActiveRecord avec des jointures multiples ne reconnaissant pas les relations

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

le résultat dans la console Rails est:

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

il semble que l'association est faite. Qu'est-ce que je fais mal? la requête signifie-t-elle réellement que toutes les instructions join() doivent se rapporter à Student, ou devrait-elle retracer les liens relationnels?

Professeur page show:

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

modèles:

inscription

class Enrollment < ApplicationRecord 
    belongs_to :section 
    belongs_to :student 
end 

étudiants:

class Student < ApplicationRecord 
    has_many :enrollments 
end 

Professeur:

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 

Cours:

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 

Schéma:

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 

Répondre

1

Vous êtes trop .joins application. Essayez de partir de l'intérieur. Tout d'abord, trouver le cours:

Course.find_by(id: course_id) 

Ensuite, trouver toutes les sections associées à la course. Pas besoin de faire un joins ici:

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

Maintenant, vous faites votre inscription:

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

Je pense qui devrait faire l'affaire pour vous. Mais, non testé. Alors, essayez-le et voyez si cela fonctionne.

P.S .: Essayez de publier uniquement le code le plus pertinent. Ce n'est pas tellement amusant de faire le tri dans un tas de trucs superflus.

+0

merci, je vais le tester maintenant. n'était pas exactement sûr de ce qui était pertinent dans ce cas, si savoir comment les entités étaient liées était pertinent ou non, de sorte qu'ils ont été inclus. – StillLearningToCode

0

ami.

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

ou

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

1

Une autre façon de le faire est d'ajouter quelques associations à votre modèle 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 

Vous pouvez trouver tous les étudiants inscrits dans un course avec:

Student.enrolled_in_course(course) 
+0

C'est beaucoup mieux que la réponse acceptée. – max