Rails中BookingsController#create获取hotel_id失败报错求助
Let's resolve this issue step by step — the core problem is that your create action isn't receiving the hotel_id parameter, so Rails can't locate the associated Hotel. Here's how to fix it properly:
1. Ensure Proper Nested Routing
First, make sure your bookings routes are nested under hotels in config/routes.rb. This ensures the hotel_id is included in the URL when accessing booking actions:
resources :hotels do resources :bookings, only: [:new, :create] # Add other actions like :show if needed end
This generates URLs like /hotels/:hotel_id/bookings/new (for the form) and /hotels/:hotel_id/bookings (for the POST request), which will automatically pass hotel_id in params.
2. Update the new Action to Build Associated Booking
Modify your new action to build the booking directly from the hotel object. This establishes the association upfront, so the form will automatically include the hotel_id when submitted:
def new @hotel = Hotel.find(params[:hotel_id]) @booking = @hotel.bookings.new # This links the booking to the hotel immediately # Simplify room queries (no need for joins since we already have @hotel) room = @hotel.room # Use @hotel.rooms if Hotel has many Rooms @single = room.pluck(:single_bedroom_num) @double = room.pluck(:double_bedroom_num) @suite = room.pluck(:suite_room_num) @dormitory = room.pluck(:dormitory_room_num) # Remove the s/d/su/dor variables — they won't exist in the GET request for new end
3. Fix the Form to Submit hotel_id
In your app/views/bookings/new.html.erb form, use the nested model syntax to ensure the hotel_id is included in the form data:
<%= form_with(model: [@hotel, @booking], local: true) do |form| %> # Your existing form fields (guest name, dates, room counts, etc.) # Optional: If you want to explicitly add a hidden field (though the nested model should handle this) <%= form.hidden_field :hotel_id, value: @hotel.id %> <%= form.submit "Book Now" %> <% end %>
4. Update the create Action to Use the Association
Modify the create action to use the hotel's booking association, which automatically sets the hotel_id without relying on it being in the submitted params:
def create @hotel = Hotel.find(params[:hotel_id]) @booking = @hotel.bookings.new(book_params) # Association sets hotel_id automatically if @booking.save flash[:notice] = "Booked successfully!" # Use flash[:notice] for redirects (flash.now is for renders) redirect_to root_path else flash.now[:alert] = "Oops, couldn't book." render :new end end
5. Verify Strong Parameters
Your existing book_params already permits :hotel_id, which is fine — but since we're using the association to set it, you don't strictly need it in the permitted list. You can keep it or remove it; either way will work.
Why This Works
- Nested routes ensure
hotel_idis present in the request URL, soparams[:hotel_id]exists in bothnewandcreateactions. - Building the booking from
@hotel.bookings.newestablishes the association, so the form includes the necessaryhotel_iddata (either via the nested form URL or the hidden field). - Using the association in
createguarantees the booking is linked to the correct hotel, even if thehotel_idwasn't explicitly submitted (though it will be, thanks to the form setup).
内容的提问来源于stack exchange,提问作者Vridhi Sahu

