我的 "unpermitted parameter: :passenger" Rails 错误来自哪里?
Where is my "unpermitted parameter: :passenger" Rails error coming from?
我正在构建一个带有 Rails 的航班预订应用程序,可以让您 select 机场、日期和乘客数量。一旦你 select 机场和日期,它会给你单选按钮 select 你想要的航班,一旦你点击提交,你就会被带到一个预订确认页面,要求你提供乘客信息.
确认页面 (bookings#new) 有一个嵌套表单,用于将乘客包含在预订对象中。为此,我首先设置了以下模型和关联:
class Passenger < ApplicationRecord
belongs_to :booking
end
class Booking < ApplicationRecord
belongs_to :flight
has_many :passengers
accepts_nested_attributes_for :passengers
end
以及导致以下架构表的相关迁移:
create_table "bookings", force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "flight_id"
t.integer "passenger_id"
end
create_table "passengers", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "booking_id"
t.index ["booking_id"], name: "index_passengers_on_booking_id"
end
据我了解,流程是这样的:
用户 select 的航班 -> 用户提交航班,通过我控制器上的 #new 方法转到 Booking#new:
class BookingsController < ApplicationController
def new
@booking = Booking.new
@flight = Flight.find(params[:flight_id])
params[:passengers_number].to_i.times do #params passed from select flight page
@booking.passengers.build
end
end
然后,我构建的表单将接管 new.html.erb:
<%= form_with model: @booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: @flight.id %>
<% @booking.passengers.each_with_index do |passenger, index| %>
<%= f.fields_for passenger, index: index do |form| %>
<h4><%= "Passenger #{index+1}"%> <br> </h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
我填写姓名和电子邮件,单击 'Confirm details',我在终端上收到此错误:
Unpermitted parameter: :passenger
为什么?我在我的 Booking 模型上设置了 accepts_nested_attributes_for :passengers
,我的 booking_params 方法是:
def booking_params
params.require(:booking).permit(:flight_id,
:passengers_attributes => [:name, :email, :passenger_id, :created_at, :updated_at])
end
我的#create 方法是:
def create
@booking = Booking.new(booking_params)
respond_to do |format|
if @booking.save
format.html { redirect_to @booking, notice: "booking was successfully created." }
format.json { render :show, status: :created, location: @booking }
else
format.html { redirect_to root_path, alert: "booking failed, #{@booking.errors.full_messages.first}" , status: :unprocessable_entity }
format.json { render json: @booking.errors, status: :unprocessable_entity }
end
end
end
有什么我没有适当允许的吗?请注意,如果我将 booking_params
设置为 params.require(:booking).permit!
,它会给我一个 unknown attribute 'passenger' for Booking
错误。但至少据我所知,我已经定义了关于乘客和预订的关联和数据库。
提前致谢
编辑:产生错误的服务器日志是:
Started POST "/bookings" for ::1 at 2021-08-27 17:52:17 +0300
Processing by BookingsController#create as HTML
Parameters: {"authenticity_token"=>"[FILTERED]", "booking"=>{"flight_id"=>"5", "passenger"=>{"0"=>{"name"=>"Jason Smason", "email"=>"jason@ymail.com"}, "1"=>{"name"=>"Joe Smith", "email"=>"Joe@smith.com"}}}, "commit"=>"Confirm details"}
Unpermitted parameter: :passenger
Edit2:我听从了 PCurell 的建议,将我的 fields_for
更改为 <%= f.fields_for :passengers, passenger, index: index do |form| %>
,并将我的预订参数更改为 :passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
产生了不同的错误:Unpermitted parameter: passengers_attributes'. So I changed my controller's
booking_params` 到:
def booking_params
params.require(:booking).permit(:flight_id,
:passengers_attributes => [:name, :email, :passenger_id, :created_at, :updated_at],
:passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
end
有了这个,我成功地创建了一个有 2 名乘客的预订。然而,乘客一片空白;他们的 name
和 email
为零。日志说:
Parameters: {"authenticity_token"=>"[FILTERED]", "booking"=>{"flight_id"=>"1", "passengers_attributes"=>{"0"=>{"0"=>{"name"=>"John Smith", "email"=>"John@smith.com"}}, "1"=>{"1"=>{"name"=>"Burger King", "email"=>"bk@bk.com"}}}}, "commit"=>"Confirm details"}
Unpermitted parameter: :0
Unpermitted parameter: :1
我可能能够硬编码 :0 和 :1 以通过,但肯定不是 Rails 方式。有没有办法动态地让他们进来?还是我整件事都做错了?
正如@Rockwell Rice 在他的评论中提到的那样:
这里的问题是您允许了错误的参数。
def booking_params
params.require(:booking).permit(:flight_id,
:passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
end
应该可以。
尽管您可能会遇到另一个错误。
我认为您 fields_for 构建错误。
这应该是您要查找的内容(您不必更改 booking_params)
<%= form_with model: @booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: @flight.id %>
<% @booking.passengers.each_with_index do |passenger, index| %>
<%= f.fields_for :passengers, passenger, index: index do |form| %>
<h4><%= "Passenger #{index+1}"%> <br> </h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
以上应该有效。
如果您不太关心索引,这也行得通:
<%= form_with model: @booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: @flight.id %>
<%= f.fields_for @booking.passengers do |form| %>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
您对 fields_for
的用法不正确。当您在指南中查看 the example 时,您会注意到如果用于集合,则无需用 .each
将其包装。
10.2 Nested Forms
The following form allows a user to create a Person
and its
associated addresses.
<%= form_with model: @person do |form| %>
Addresses:
<ul>
<%= form.fields_for :addresses do |addresses_form| %>
<li>
<%= addresses_form.label :kind %>
<%= addresses_form.text_field :kind %>
<%= addresses_form.label :street %>
<%= addresses_form.text_field :street %>
...
</li>
<% end %>
</ul>
<% end %>
When an association accepts nested attributes fields_for
renders its block once for every element of the association. In particular,
if a person has no addresses it renders nothing. A common pattern is
for the controller to build one or more empty children so that at
least one set of fields is shown to the user. The example below would
result in 2 sets of address fields being rendered on the new person
form.
def new
@person = Person.new
2.times { @person.addresses.build }
end
将此应用于您的代码时,删除 .each
包装并将 passenger
更改为 :passengers
应该可以解决问题。您可以通过传递给 fields_for
块的 FormBuilder
实例 (form
) 访问 index
。
<%= form_with model: @booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: @flight.id %>
<%= f.fields_for :passengers do |form| %>
<h4>Passenger <%= form.index + 1 %></h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
我正在构建一个带有 Rails 的航班预订应用程序,可以让您 select 机场、日期和乘客数量。一旦你 select 机场和日期,它会给你单选按钮 select 你想要的航班,一旦你点击提交,你就会被带到一个预订确认页面,要求你提供乘客信息.
确认页面 (bookings#new) 有一个嵌套表单,用于将乘客包含在预订对象中。为此,我首先设置了以下模型和关联:
class Passenger < ApplicationRecord
belongs_to :booking
end
class Booking < ApplicationRecord
belongs_to :flight
has_many :passengers
accepts_nested_attributes_for :passengers
end
以及导致以下架构表的相关迁移:
create_table "bookings", force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "flight_id"
t.integer "passenger_id"
end
create_table "passengers", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "booking_id"
t.index ["booking_id"], name: "index_passengers_on_booking_id"
end
据我了解,流程是这样的: 用户 select 的航班 -> 用户提交航班,通过我控制器上的 #new 方法转到 Booking#new:
class BookingsController < ApplicationController
def new
@booking = Booking.new
@flight = Flight.find(params[:flight_id])
params[:passengers_number].to_i.times do #params passed from select flight page
@booking.passengers.build
end
end
然后,我构建的表单将接管 new.html.erb:
<%= form_with model: @booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: @flight.id %>
<% @booking.passengers.each_with_index do |passenger, index| %>
<%= f.fields_for passenger, index: index do |form| %>
<h4><%= "Passenger #{index+1}"%> <br> </h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
我填写姓名和电子邮件,单击 'Confirm details',我在终端上收到此错误:
Unpermitted parameter: :passenger
为什么?我在我的 Booking 模型上设置了 accepts_nested_attributes_for :passengers
,我的 booking_params 方法是:
def booking_params
params.require(:booking).permit(:flight_id,
:passengers_attributes => [:name, :email, :passenger_id, :created_at, :updated_at])
end
我的#create 方法是:
def create
@booking = Booking.new(booking_params)
respond_to do |format|
if @booking.save
format.html { redirect_to @booking, notice: "booking was successfully created." }
format.json { render :show, status: :created, location: @booking }
else
format.html { redirect_to root_path, alert: "booking failed, #{@booking.errors.full_messages.first}" , status: :unprocessable_entity }
format.json { render json: @booking.errors, status: :unprocessable_entity }
end
end
end
有什么我没有适当允许的吗?请注意,如果我将 booking_params
设置为 params.require(:booking).permit!
,它会给我一个 unknown attribute 'passenger' for Booking
错误。但至少据我所知,我已经定义了关于乘客和预订的关联和数据库。
提前致谢
编辑:产生错误的服务器日志是:
Started POST "/bookings" for ::1 at 2021-08-27 17:52:17 +0300
Processing by BookingsController#create as HTML
Parameters: {"authenticity_token"=>"[FILTERED]", "booking"=>{"flight_id"=>"5", "passenger"=>{"0"=>{"name"=>"Jason Smason", "email"=>"jason@ymail.com"}, "1"=>{"name"=>"Joe Smith", "email"=>"Joe@smith.com"}}}, "commit"=>"Confirm details"}
Unpermitted parameter: :passenger
Edit2:我听从了 PCurell 的建议,将我的 fields_for
更改为 <%= f.fields_for :passengers, passenger, index: index do |form| %>
,并将我的预订参数更改为 :passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
产生了不同的错误:Unpermitted parameter: passengers_attributes'. So I changed my controller's
booking_params` 到:
def booking_params
params.require(:booking).permit(:flight_id,
:passengers_attributes => [:name, :email, :passenger_id, :created_at, :updated_at],
:passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
end
有了这个,我成功地创建了一个有 2 名乘客的预订。然而,乘客一片空白;他们的 name
和 email
为零。日志说:
Parameters: {"authenticity_token"=>"[FILTERED]", "booking"=>{"flight_id"=>"1", "passengers_attributes"=>{"0"=>{"0"=>{"name"=>"John Smith", "email"=>"John@smith.com"}}, "1"=>{"1"=>{"name"=>"Burger King", "email"=>"bk@bk.com"}}}}, "commit"=>"Confirm details"}
Unpermitted parameter: :0
Unpermitted parameter: :1
我可能能够硬编码 :0 和 :1 以通过,但肯定不是 Rails 方式。有没有办法动态地让他们进来?还是我整件事都做错了?
正如@Rockwell Rice 在他的评论中提到的那样:
这里的问题是您允许了错误的参数。
def booking_params
params.require(:booking).permit(:flight_id,
:passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
end
应该可以。
尽管您可能会遇到另一个错误。
我认为您 fields_for 构建错误。
这应该是您要查找的内容(您不必更改 booking_params)
<%= form_with model: @booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: @flight.id %>
<% @booking.passengers.each_with_index do |passenger, index| %>
<%= f.fields_for :passengers, passenger, index: index do |form| %>
<h4><%= "Passenger #{index+1}"%> <br> </h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
以上应该有效。
如果您不太关心索引,这也行得通:
<%= form_with model: @booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: @flight.id %>
<%= f.fields_for @booking.passengers do |form| %>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
您对 fields_for
的用法不正确。当您在指南中查看 the example 时,您会注意到如果用于集合,则无需用 .each
将其包装。
10.2 Nested Forms
The following form allows a user to create a
Person
and its associated addresses.<%= form_with model: @person do |form| %> Addresses: <ul> <%= form.fields_for :addresses do |addresses_form| %> <li> <%= addresses_form.label :kind %> <%= addresses_form.text_field :kind %> <%= addresses_form.label :street %> <%= addresses_form.text_field :street %> ... </li> <% end %> </ul> <% end %>
When an association accepts nested attributes
fields_for
renders its block once for every element of the association. In particular, if a person has no addresses it renders nothing. A common pattern is for the controller to build one or more empty children so that at least one set of fields is shown to the user. The example below would result in 2 sets of address fields being rendered on the new person form.def new @person = Person.new 2.times { @person.addresses.build } end
将此应用于您的代码时,删除 .each
包装并将 passenger
更改为 :passengers
应该可以解决问题。您可以通过传递给 fields_for
块的 FormBuilder
实例 (form
) 访问 index
。
<%= form_with model: @booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: @flight.id %>
<%= f.fields_for :passengers do |form| %>
<h4>Passenger <%= form.index + 1 %></h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>