我的应用程序(基于Hartl Rails 5教程)具有一个has_many Rooms的User模型,而Room模型又具有has_many Students的用户模型。我有一个供用户使用学生(具有:name属性)创建房间(具有:number属性)的表单。尽管“用户”创建表单与“房间”创建表单是分开的,但是我使用了本示例中的关联代码:https://medium.com/@mindovermiles262/triple-nested-forms-in-rails-dedbcccb5799。
当我提交表格时,它返回错误“学生房间不能为空”。房间和学生之间的联系正在消失。以下是带有错误消息的已提交表单的屏幕截图:
以下是相关的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方法,但是我错了。
答案 0 :(得分:0)
移除
验证:room_id,可选:true
是解决方案。