子级的Rails 5.1 form_with三重嵌套表单子级(grandchild ??)不继承属性且未保存

时间:2018-08-26 17:58:49

标签: nested-forms ruby-on-rails-5.1

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

当我提交表格时,它返回错误“学生房间不能为空”。房间和学生之间的联系正在消失。以下是带有错误消息的已提交表单的屏幕截图: Screenshot of Students room can't be blank error

以下是相关的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

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

我在Rails 5 error message: Child-Model Parent-Model must exist中添加了:inverse_of,但这没什么区别。这个(rails 5.1: nested form validation)似乎不相关,因为它涉及一个有两个不同孩子的父母,而不是一个有孩子的父母,也有一个孩子。

在此先感谢您的帮助。

编辑:

我终于意识到错误消息“学生房间不能为空”指的是room_id为空。我从student.rb中删除了以下行:

验证:room_id,在线状态:true

我以为

belongs_to:room,可选:true

会暂时绕过validates方法,但是我错了。

1 个答案:

答案 0 :(得分:0)

移除

验证:room_id,可选:true

是解决方案。