Reputation: 13
I have a simple has many relationship established between two models. "Listings" can have many "Offers" and Offers can only have one listing. I can create listings just fine but when I create an associated "Offer" - the details from my offer form are not being saved into the database. The object itself saves, and includes the Listing ID associated with it, but nothing from the form comes through.
I've pasted most relevant code blocks, any advice would be appreciated.
Offers Controller: class OffersController < ApplicationController
def new
@listing = Listing.find(params[:id])
@offer = @listing.offers.build
end
def create
@listing = Listing.find(params[:id])
@offer = @listing.offers.create!(params[offer_params])
if @offer.save
redirect_to offer_path(:id => @offer.id)
end
end
def show
@offer = Offer.find(params[:id])
end
def index
end
private
def offer_params
params.require(:offer).permit(:offer_price, :offer_terms, :listing_id, :offer_expiration)
end
end
The Form associated with Offers
<%= @listing.street_address %> (<%= link_to "Back", listings_path %>)
<%= form_for [@offer, @listing], :url => { :action => :create, :id => @listing.id}, html: {multipart: true} do |f| %>
<div class="field">
<%= f.label :offer_price %><br>
<%= f.text_field :offer_price %>
</div>
<div class="field">
<%= f.label :offer_terms %><br>
<%= f.text_area :offer_terms %>
</div>
<div class="field">
<%= f.label :offer_expiration %><br>
<%= f.text_field :offer_expiration %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And finally, the development log entry when I hit submit on my form. As you can see, it stores the offer details properly (I think) in the params hash but when it inserts it to the database, all the offer fields are not coming along.
Started POST "/offers?id=2" for ::1 at 2015-03-11 13:40:01 -0400
Processing by OffersController#create as HTML
Parameters: {"utf8"=>"✓","authenticity_token"=>"NldTPDo/s/Jyo8SB0I6/OWYWeN0Ukf9JYQU5nASUDONcMl OQTauG+HWxsfjZ4yJLrvDxVtbUaX2sBD63BMIQtA==", "offer"=>{"offer_price"=>"988888", "offer_terms"=>"financed", "offer_expiration"=>"Never"}, "commit"=>"Create Offer", "id"=>"2"}
[1m[35mListing Load (0.2ms)[0m SELECT "listings".* FROM "listings" WHERE "listings"."id" = ? LIMIT 1 [["id", 2]]
[1m[36m (0.1ms)[0m [1mbegin transaction[0m
[1m[35mSQL (0.4ms)[0m INSERT INTO "offers" ("listing_id", "created_at", "updated_at") VALUES (?, ?, ?) [["listing_id", 2], ["created_at", "2015-03-11 17:40:01.967717"], ["updated_at", "2015-03-11 17:40:01.967717"]]
[1m[36m (0.8ms)[0m [1mcommit transaction[0m
[1m[35m (0.1ms)[0m begin transaction
[1m[36m (0.0ms)[0m [1mcommit transaction[0m
Redirected to http://localhost:3000/offers/33
Completed 302 Found in 36ms (ActiveRecord: 2.6ms)
Upvotes: 1
Views: 692
Reputation: 281
In your def create
replace params[offer_params]
with just offer_params
.
def create
@listing = Listing.find(params[:id])
@offer = @listing.offers.build(offer_params) # <- the important change
if @offer.save
redirect_to offer_path(:id => @offer.id)
else
flash[:error] = @offer.errors.full_messages
render :new
end
end
Additional
.create!
-> .build
.build
instead of .create!
in your create action. .create!
calls a .save
prematurely to your if statement causing double the database queries..create!
does not let errors fail silently; meaning that if validation on your Offer
fails your application will break.Render :new if save fails
Upvotes: 0