首页 > 解决方案 > 我的“不允许的参数::passenger”Rails 错误来自哪里?

问题描述

我正在使用 Rails 构建一个航班预订应用程序,让您可以选择机场、日期和乘客人数。一旦您选择了机场和日期,它会为您提供单选按钮来选择您想要的航班,一旦您点击提交,您将被带到一个预订确认页面,您需要提供乘客信息。

确认页面(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

据我了解,流程是这样的:用户选择航班-> 用户提交航班,通过我控制器上的#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 %>

我用姓名和电子邮件填写它,单击“确认详细信息”,我在终端上收到此错误:

Unpermitted parameter: :passenger

为什么?我已经设置accepts_nested_attributes_for :passengers了我的 Booking 模型,我的 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_paramsparams.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_forto <%= 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` to:

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 名乘客的预订。但是,乘客是空白的;他们nameemail为零。日志说:

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 方式。有没有办法让他们动态进入?还是我做错了整个事情?

标签: ruby-on-railsrubyactiverecordruby-on-rails-6

解决方案


你的用法fields_for不正确。当您查看指南中的示例时,您会注意到没有必要用.eachif 来包装它作为集合。

10.2 嵌套表单

以下表单允许用户创建一个Person及其关联的地址。

<%= 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 %>

当一个关联接受嵌套属性时,fields_for它会为关联的每个元素呈现一次它的块。特别是,如果一个人没有地址,则它不会呈现任何内容。一种常见的模式是控制器构建一个或多个空子,以便向用户显示至少一组字段。下面的示例将导致在新人员表单上呈现 2 组地址字段。

def new
  @person = Person.new
  2.times { @person.addresses.build }
end

将其应用于您的代码时,删除.each包装器并更改passenger:passengers应该可以解决问题。您可以通过传递给块indexFormBuilder实例 ( ) 访问。formfields_for

<%= 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 %>

推荐阅读