Dan Elliman
Dan Elliman

Reputation: 13

Rails fails to save object information on create method

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

Answers (1)

D3RPZ1LLA
D3RPZ1LLA

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

  • Use .build instead of .create! in your create action. .create! calls a .save prematurely to your if statement causing double the database queries.
  • Additionally .create! does not let errors fail silently; meaning that if validation on your Offer fails your application will break.

Render :new if save fails

  • If model saving fails it's common to rerender the :new view to prevent a missing :create template error, to display the save errors (i.e. - "Your offer must contain a price") and to give the user an opportunity to correct their request.

Upvotes: 0

Related Questions