首页 > 解决方案 > Rails:路由“课程”->“章节”->“课程”

问题描述

我是 Ruby on Rails 的新手。我尝试连接 3 个表。

我的模型:

课程.rb:

class Course < ApplicationRecord
has_many :chapters
has_many :lessons, through: :chapters
end

章节.rb

class Chapter < ApplicationRecord
belongs_to :course
belongs_to :lesson

end

课程.rb

class Lesson < ApplicationRecord
has_many :chapters
has_many :courses, through: :chapters
end

我的课程控制器如下所示:

class CourseController < ApplicationController
def index
end

def show

@course = Course.find(params[:id])
@chapters = @course.chapters
@lessons = @course.lessons



end
end

和 show.html.erb

<% @chapters.each do |c| %>
<%= c.chapter %>
<%= link_to "lektionen", c %>
<% end %>

我可以看到我的课程列表。那是有效的。我也可以看到章节。但出于任何原因,它不会转发 id 以在这些模型之间建立关系。

Chapter Controller:
class ChapterController < ApplicationController
def index
end

def show
@chapters = Chapter.find(params[:id])
@lessons = @chapters.lessons
end
end

我想转发课程的ID,以便章节<<课程是课程的孩子。

-courses 
-- chapters 
--- lessons

我的架构:

ActiveRecord::Schema.define(version: 2021_04_11_090326) do

  create_table "chapters", force: :cascade do |t|
    t.string "chapter"
    t.integer "course_id", null: false
    t.integer "lesson_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["course_id"], name: "index_chapters_on_course_id"
    t.index ["lesson_id"], name: "index_chapters_on_lesson_id"
  end

  create_table "courses", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "lessons", force: :cascade do |t|
    t.string "title"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  add_foreign_key "chapters", "courses"
  add_foreign_key "chapters", "lessons"
end

我的路线.rb

Rails.application.routes.draw do
  get 'chapter/index'
  get 'chapter/show'
  get 'course/index'
  get 'course/show'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  
  resources :course 
    resources :chapter
  resources :lessons
end

如果我点击“courses#show”动作,我可以看到章节。如果我单击一章,则会出现此错误:

#Chapter:0x000055f7aeefbe50 的未定义方法“课程”

我只想显示属于特定章节的课程,并且该章节与课程相关。

但我无法让这个工作。

我希望你能帮助我。

标签: ruby-on-rails

解决方案


我认为在这种情况下你应该重新考虑你的数据模型:

让它成为课程 -> 章节 -> 课程

class Course < ApplicationRecord
  has_many :chapters # a course has many chapters. alright
end

class Chapter < ApplicationRecord
  belongs_to :course # a chapter always belongs to a course
  has_many :lessons # and has many lessons ! check!
end

class Lesson < ApplicationRecord
  belongs_to :chapter # a lesson belongs to a chapter
  
  # helper method if you want to access course directly from lesson
  def course
    @course ||= chapter&.course
  end
end

数据库 您的数据库应该如下所示:建议 -> 不要chapter在章节表中命名它。打电话titlename

ActiveRecord::Schema.define(version: 2021_04_11_090326) do

  create_table "courses", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end


  create_table "chapters", force: :cascade do |t|
    t.string "title"
    t.integer "course_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["course_id"], name: "index_chapters_on_course_id"
  end

      
  create_table "lessons", force: :cascade do |t|
    t.string "title"
    t.integer "chapter_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["chapter_id"], name: "index_lessons_on_chapter_id"
  end

end

通过此设置,您可以使用良好的层次结构。

绘制路线:

Rails.application.routes.draw do
  resources :courses
  resources :chapters
  resources :lessons
end

如果你想在 url 中创建层次结构,你可以做一些更高级的事情

Rails.application.routes.draw do
  # use this if you know what you are doing :D
  resources :courses do
    resources :chapters do
      resources :lessons
    end
  end
end

您的控制器:

class CourseController < ApplicationController
  def index
    courses
  end

  def show
    course
  end

  protected
  # get all courses
  def courses
    @courses ||= Course.order(:name)
  end
  
  # find course by id
  def course
    @course ||= courses.find(params[:id])
  end
end

在你看来views/courses/show.html.erb

<h1><%= @course.name %></h1>
<% @course.chapters.each do |chapter| %>
  <h2><%= chapter.title %></h2>
  <% chapter.lessons.each do |lesson| %>
    <%= link_to "Lesson: " + lesson.title, lesson_url(lesson) %>
  <% end %>
<% end %>

N+1 问题: 为避免在呈现此层次结构时出现 N+1 问题,请更改控制器并将包含添加到查询中:

  def course
    @course ||= courses.includes(chapters: :lessons).find(params[:id])
  end

我希望这可以为您提供一个干净的数据模型的良好开端。


推荐阅读