Rails 5.1 form_with 三重嵌套形式 child (grandchild??) of child 不继承属性且不保存

Rails 5.1 form_with triple nested form child (grandchild??) of child not inheriting attribute and not saving

我的应用程序(基于 Hartl Rails 5 教程)有一个 has_many Rooms 的 User 模型,以及 has_many Students 的 Room 模型。我有一个表格供用户与学生(具有:name 属性)创建一个房间(具有:number 属性)。尽管用户创建表单与房间创建表单是分开的,但我使用了此示例中的关联代码:https://medium.com/@mindovermiles262/triple-nested-forms-in-rails-dedbcccb5799.

当我提交表单时 returns 错误 "Students room can't be blank"。 Room 和 Student 之间的关联在某处丢失了。以下是带有错误消息的已提交表单的屏幕截图:

这里是相关的user.rb代码:

class User < ApplicationRecord
has_many        :rooms, dependent: :destroy
has_many        :students, through: :rooms
accepts_nested_attributes_for   :rooms, allow_destroy: true
accepts_nested_attributes_for   :students, allow_destroy: true

...

end

users_controller.rb

    private

def user_params
  params.require(:user).permit(:name, :email, :school, :password,
                               :password_confirmation,
                               :rooms_attributes => [:id, :number, 
                               :students_attributes => [:id, :name]
                               ] )

end

room.rb:

    class Room < ApplicationRecord
  belongs_to                        :user, optional: true
  has_many                          :students, dependent: :destroy, inverse_of:  
                                    :room
  accepts_nested_attributes_for     :students, allow_destroy: true
  default_scope ->                  { order(number: :asc) }
  validates                         :number, presence: true
  validates                         :user_id, presence: true    
end

rooms_controller.rb

    class RoomsController < ApplicationController

before_action :logged_in_user, only: [:create, :destroy, :edit, :update, :show]
before_action :correct_user,   only: [:show]

    def new
        @room = current_user.rooms.build if logged_in?
        @student = @room.students.build
    end

  def create

    @room = current_user.rooms.build(room_params)


    if @room.save && @student.save
      flash[:success] = "New class created."
      redirect_to current_user
    else
      render 'rooms/new'
    end
  end

  def destroy
  end

  def edit
  end

  def update
    @room = Room.find(params[:id])
    if @room.update_attribute(room_params)
        redirect_to @room
        flash[:success] = "Class updated."
    end
  end

  def show
    @user = User.find(params[:id])
    @rooms = @user.rooms
    # @number = @rooms.number
  end

  private

    def room_params
      params.require(:room).permit(:number, :students_attributes => [:id, :name])

    end

end

来自sessions_helper.rb的current_user方法:

      def current_user
    if (user_id = session[:user_id])
      @current_user ||= User.find_by(id: user_id)
    elsif (user_id = cookies.signed[:user_id])
      user = User.find_by(id: user_id)
      if user && user.authenticated?(:remember, cookies[:remember_token])
        log_in user
        @current_user = user
      end
    end
  end

student.rb:

    class Student < ApplicationRecord
  belongs_to        :room, optional: true, inverse_of: :students
  validates         :name, presence: true, length: { maximum: 50 }
  validates         :room_id, presence: true
end

students_controller.rb

    class StudentsController < ApplicationController

    before_action   :logged_in_user, only: [:create, :destroy, :edit, :update, :show]
    before_action   :correct_user,   only: [:show]




    def new
        @room = current_user.rooms.build if logged_in?
        @student = @room.students.build
    end

    def create

        if @student.save
         flash[:success] = "New student created."
        redirect_to current_user

        else

            render 'students/new'
        end
    end

    def show
    end

      private

    def student_params
      params.require(:student).permit(:name)
    end
end

房间创建表单,rooms\new。html.erb:

    <% provide(:title, 'Create a class') %>
    <h1>Create a class</h1>

    <%= form_with(model: @room, local: true) do |f| %>

        <%= render 'shared/error_messages', object: f.object %>

          <%= f.label :number, "Class number" %>
          <%= f.number_field :number, class: 'form-control' %>

           <%= f.fields_for :students do |s| %>
            <%= s.label :name, "Student name" %>
            <%= s.text_field :name, class: 'form-control' %>
          <% end %>


      <%= f.submit "Create class", class: "btn btn-primary" %>
      <%= params.inspect %>
<% end %>

config\routes.rb:

    Rails.application.routes.draw do



  get 'password_resets/new'

  get 'password_resets/edit'

  get 'sessions/new'



      root 'static_pages#home'
    get '/signup',        to: 'users#new'
    post '/signup',       to: 'users#create'
    get    '/login',      to: 'sessions#new'
    post   '/login',      to: 'sessions#create'
    delete '/logout',     to: 'sessions#destroy'
    get '/showall',       to: 'users#index'
    get '/createroom',    to: 'rooms#new'
    post '/createroom',   to: 'rooms#create'
    get 'createstudent',  to: 'students#new'
    get 'createstudent',  to: 'students#create'


    resources :users
    resources :account_activations, only: [:edit]
    resources :password_resets,     only: [:new, :create, :edit, :update]
    resources :rooms
    resources :students

end

和development.log:

Processing by RoomsController#new as 
  Rendering rooms/new.html.erb within layouts/application
  Rendered shared/_error_messages.html.erb (1.0ms)
  Rendered rooms/new.html.erb within layouts/application (388.0ms)
  Rendered layouts/_rails_default.html.erb (244.0ms)
  Rendered layouts/_shim.html.erb (1.0ms)
  Rendered layouts/_header.html.erb (1.0ms)
  Rendered layouts/_footer.html.erb (1.0ms)
Completed 200 OK in 2938ms (Views: 2513.1ms | ActiveRecord: 12.0ms)


Processing by RoomsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"henh7dclciYRcZE6xRFfdSHBPQuRmO03eXXEsmRkSSI25uqkMSo6WFwthixdEzDNSNjY5pPmcIYwi5nmFZirMg==", "room"=>{"number"=>"200", "students_attributes"=>{"0"=>{"name"=>"Roo"}}}, "commit"=>"Create class"}
  Rendering rooms/new.html.erb within layouts/application
  Rendered shared/_error_messages.html.erb (1.0ms)
  Rendered rooms/new.html.erb within layouts/application (35.0ms)
  Rendered layouts/_rails_default.html.erb (237.0ms)
  Rendered layouts/_shim.html.erb (0.0ms)
  Rendered layouts/_header.html.erb (1.0ms)
  Rendered layouts/_footer.html.erb (1.0ms)
Completed 200 OK in 3283ms (Views: 494.7ms | ActiveRecord: 3.0ms)

I added :inverse_of per but that made no difference. This () does not appear relevant, b/c it involves a parent with two different children, not a parent 有一个 child 也有一个 child.

在此先感谢您的帮助。

编辑:

我终于意识到错误消息 "Students room can't be blank" 指的是 room_id 是空白的。我从 student.rb 中删除了以下行:

验证:room_id,存在:真

我以为

belongs_to:房间,可选:true

会暂时绕过验证方法,但我错了。

删除

验证:room_id,可选:真

是解决方案。