Ассоциации Rails — создание новой записи через форму с помощью belongs_to

#ruby-on-rails #ruby #associations

#ruby-on-rails #ruby #ассоциации

Вопрос:

У меня есть модель курса:

 class Course < ApplicationRecord
  has_many :sub_courses

  validates :title, presence: true

  # Course associated to SubCourse via 'sub_course_id' on Course table
end
  

И модель подкурса:

 class SubCourse < ApplicationRecord
  belongs_to :course

  # SubCourse associated to Course via 'course_id' on SubCourse table
end

  

На courses.show.html (страница конкретного курса, например, admin / courses / 1) у меня есть кнопка, которая ссылается на новую страницу дополнительного курса

 %table
  %tr
    %td= @course.title
    %td= @course.description

= button_to "Add New Sub Course", new_admin_sub_course_path(course_id: @course.id), method: :post
  

Новая форма страницы sub_course sub_courses.new.html .

 = form_for @sub_course, url: admin_sub_courses_path do |f|
  = f.label :title
  = f.text_field :title
  = f.label :description
  = f.text_field :description
  = f.submit
  

При переходе на новую страницу дополнительного курса я вижу ошибку No route matches [POST] "/admin/sub_courses/new"

Мой sub_course_controller.rb выглядит так:

 def new
    @course = Course.find(params.require(:course_id))
    @sub_course = @course.sub_course.new
  end

  def create
    if @sub_course.save
      redirect_to admin_sub_courses_path, notice: "saved"
    else
      render "new"
    end
  end
  

И мои маршруты выглядят так:

 namespace :admin do
    resources :courses, { :only => [:index, :new, :create, :edit, :destroy, :update, :show] }
    resources :sub_courses 
  end
  

Как мне успешно создать sub_course, который автоматически связан с его курсом с исходной страницы показа, с которой я пришел?

Структура схемы выглядит следующим образом:

   create_table "courses", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "title"
    t.string "description"
    t.integer "sub_course_id"
  end

  create_table "sub_courses", force: :cascade do |t|
    t.string "title"
    t.text "description"
    t.string "question"
    t.string "possible_answer"
    t.string "correct_answer"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "course_id"
  end
  

После запуска маршрутов рейка для вспомогательных курсов:

 admin_sub_courses GET    /admin/sub_courses(.:format)                                                             admin/sub_courses#index
                          POST   /admin/sub_courses(.:format)                                                             admin/sub_courses#create
     new_admin_sub_course GET    /admin/sub_courses/new(.:format)                                                         admin/sub_courses#new
    edit_admin_sub_course GET    /admin/sub_courses/:id/edit(.:format)                                                    admin/sub_courses#edit
         admin_sub_course GET    /admin/sub_courses/:id(.:format)                                                         admin/sub_courses#show
                          PATCH  /admin/sub_courses/:id(.:format)                                                         admin/sub_courses#update
                          PUT    /admin/sub_courses/:id(.:format)                                                         admin/sub_courses#update
                          DELETE /admin/sub_courses/:id(.:format)                                                         admin/sub_courses#destroy
  

Ответ №1:

Прежде всего, я бы проверил результат rake routes |grep sub_courses .

Однако, на первый взгляд, мне кажется, что существует проблема присвоения значения в sub_course контроллере. Я бы попытался реорганизовать ее следующим образом:

   before_action :set_course, only: [:new, :create]

  def new
     @sub_course = @course.sub_courses.new 
  end

  def create
     @sub_course = @course.sub_courses.new(sub_course_params)
     if @sub_course.create!(sub_course_params)
      redirect_to admin_sub_courses_path, notice: "saved"
    else
      render "new"
    end
  end

private

def sub_course_params
  params.require(:sub_course).permit(:title, :description, :question, :possible_answer, :correct_answer, :course_id)
end

def set_course
 @course = Course.find(params[:course_id])
end
  

Как вы видите, я удалил строку с Course.find(params.require(:course_id)) с правильным синтаксисом для поиска записи через параметры.
params.require Синтаксис вместо этого используется строгими параметрами, которые необходимо определить, чтобы фактически сохранять данные из форм в записи в базе данных.

Смотрите https://api.rubyonrails.org/classes/ActionController/StrongParameters.html

Затем я переместил @course назначение в частный метод set_course , таким образом, назначение выполняется только один раз и совместно используется методами, которым это необходимо.

Комментарии:

1. К сожалению, это не решает проблему для меня. Все еще сталкиваясь с ошибкой No route matches [POST] "/admin/sub_courses/new" Я думал, что #new никогда не предполагалось, что это СООБЩЕНИЕ? — Я обновил начальный пост маршрутами grep