简体   繁体   中英

custom query in active record with multiple joins

I am very new to rails and active record so I'm probably doing something wrong, but... using the schema below, I want to create a list of courses in the outer do loop, then list each student enrolled in the course with the inner do loop. I m not sure if this approach will work, but this error keeps popping up:

ActionView::Template::Error (undefined method `enrollments' for #):

it seems that the association is made. what am i doing wrong?

Professor show page:

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

models:

enrollment

class Enrollment < ApplicationRecord
  belongs_to :section
  belongs_to :student
end

Student:

class Student < ApplicationRecord
  has_many :enrollments
end

Professor:

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

Course:

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

Schema:

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

enrollment belongs_to user, there is no need to use each on single record rather it will throw error. You can use below code.

<% course.sections.each do |section| %>
    <% section.enrollments.each do |enrollment| %>
        <p><% enrollment.student.name %></p>
    <% end %>
<% end %>

Sean's answer is almost correct but since enrollments belongs_to student you would use the singular form enrollment.student . but more simply you can just call student from inside enrollments block.

<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.each do |section| %>
            <% section.enrollments.each do |enrollment| %>                  
                <p><% enrollment.student.name %></p>                 
            <% end %>
          <% end %>
        </div>
    <% end %>
</div>
<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.each do |section| %>
            <% section.enrollments.each do |enrollment| %>
              <p><% enrollment.student.name %></p>
            <% end %>
          <% end %>
        </div>
    <% end %>
</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM