mgreschke
mgreschke

Reputation: 189

rails 4 nested forms don't save

I know there's a lot of open questions regarding this around here already but none really helped me.

My main model is being saved properly, all the data is in the post-data, but it just doesn't save the nested models!

Thanks heaps.. Is it anything about the permitted parameters or attr_accessors? Something I suspect.. I didn't really find any documentation on that..

This is my code:

products_controller.rb

def product_params
    params.require(:product).permit(:title, :description, :netprice, :vat, :price, :unit_count,         :unit, :category, :img, :origin, :originid, :producer, :stock, :discount, :stories_attributes, :origins_attributes, :id)
    end
end

def new
    @product = Product.new
    3.times { @product.stories.build }
    @product.origins.build
    @categories = []
    Category.all.each do |category|
    @categories.push([category.name, category.name])
    end

end

def create
    @product = Product.new(product_params)
    respond_to do |format|
    if @product.save
        format.html { redirect_to @product, notice: 'Product was successfully created.' }
        format.json { render action: 'show', status: :created, location: @product }
    else
        format.html { render action: 'new' }
        format.json { render json: @product.errors, status: :unprocessable_entity }
    end
    end
end

origin.rb

class Origin < ActiveRecord::Base
belongs_to :product
end

product.rb

class Product < ActiveRecord::Base
    attr_accessor :stories_attributes, :origins_attributes
    has_many :stories
    has_many :origins
    accepts_nested_attributes_for :stories, allow_destroy:true, :reject_if => lambda { |a|     a[:text].blank?}
    accepts_nested_attributes_for :origins, allow_destroy:true, :reject_if => lambda {|a|      a[:city].blank?}

story.rb

class Story < ActiveRecord::Base
    belongs_to :product

end

relevant part of the form

  <section class="product-story-section">
  <%= f.fields_for :stories do |builder| %>
  <fieldset>
    <%= builder.label :yindex, "Y-Index" %><br>
    <%= builder.text_field :yindex %><br>
     <%= builder.label :description, "Story-Text" %><br>
    <%= builder.text_area :description %><br>
     <%= builder.label :img, "Bild-URL" %><br>
    <%= builder.text_field :img %><br>
    <%= builder.hidden_field :productid, value:"1" %><br>
  </fieldset>
<% end %>
</section>
<hr>
<%= f.fields_for :origins do |builder| %>
  <fieldset>
    <%= builder.label :city, "Stadt" %><br>
    <%= builder.text_field :city %><br>
    <%= builder.label :country, "Land" %><br>
    <%= builder.text_area :country %><br>
    <%= builder.label :geolat, "Geolocation Latitude" %><br>
    <%= builder.text_field :geolat %><br>
    <%= builder.label :geolng, "Geolocation Longitude" %><br>
    <%= builder.text_field :geolng %><br>
  </fieldset>
<% end %>


  Started POST "/products" for 127.0.0.1 at 2013-12-24 21:01:16 +0100
  Processing by ProductsController#create as HTML
  Parameters: {"utf8"=>"✓",    "authenticity_token"=>"90MXIlzOQg6AcTwwYOkfNsfPuSt1/9UHjqZwHVRnET4=", "product"=>    {"title"=>"9", "description"=>"9", "netprice"=>"9", "vat"=>"9", "price"=>"9",    "unit_count"=>"9", "unit"=>"9", "img"=>"", "originid"=>"99", "origin"=>"", "producer"=>"9",     "stock"=>"9", "discount"=>"9", "stories_attributes"=>{"0"=>{"yindex"=>"9", "description"=>"9",    "img"=>"9", "productid"=>"1"}, "1"=>{"yindex"=>"9", "description"=>"9", "img"=>"9",   "productid"=>"1"}, "2"=>{"yindex"=>"9", "description"=>"9", "img"=>"9", "productid"=>"1"}},  "origins_attributes"=>{"0"=>{"city"=>"9", "country"=>"", "geolat"=>"9", "geolng"=>"9"}}},  "commit"=>"Create Product"}
Unpermitted parameters: img, productid
Unpermitted parameters: img, productid
Unpermitted parameters: img, productid
(0.1ms)  BEGIN
  SQL (0.3ms)  INSERT INTO `products` (`created_at`, `description`, `discount`, `img`,    `netprice`, `origin`, `originid`, `price`, `producer`, `stock`, `title`, `unit`, `unit_count`, `updated_at`, `vat`) VALUES ('2013-12-24 20:01:16', '9', 9.0, '', 9.0, '', 99, 9.0, '9', 9, '9', '9', 9, '2013-12-24 20:01:16', 9.0)
   (0.5ms)  COMMIT
Redirected to http://localhost:3000/products/1
Completed 302 Found in 46ms (ActiveRecord: 0.9ms)

New error msg

`attr_accessible` is extracted out of Rails into a gem. Please use new recommended protection      model for params(strong_parameters) or add `protected_attributes` to your Gemfile to use old one.

Upvotes: 0

Views: 562

Answers (1)

vee
vee

Reputation: 38645

You have an extra end in your product_params method. This should have raised an error.

You also need to add stories and origins attributes to the permit list:

def product_params
    params.require(:product).permit(:title, :description, :netprice, :vat, :price, :unit_count, :unit, :category, :img, :origin, :originid, :producer, :stock, :discount, stories_attributes: [:yindex, :description, :image], origins_attributes: [ :city, :country, :geolat], :id)
end

Update: Add missing attributes to the permit list on stories_attributes and origins_attributes:

def product_params
    params.require(:product).permit(:title, :description, :netprice, :vat, :price, :unit_count, :unit, :category, :img, :origin, :originid, :producer, :stock, :discount, stories_attributes: [:yindex, :description, :img, :product_id], origins_attributes: [ :city, :country, :geolat, :geolng], :id)
end

Second update:

You also need to update your product model as follows:

class Product < ActiveRecord::Base
  attr_accessible :stories_attributes, :origins_attributes
  ...
end

Replace attr_accessor with attr_accessible. attr_accessible should be used to allow attributes to mass assignment.

In your controller's create action:

# ProductsController
def create
    @product = Product.new(product_params)
    ...
end

Your product_params definitely contains stories_attributes and origins_attributes and are passed to the Product.new method correctly, but because their attributes are not allowed to mass assignment you are not seeing associated stories and origins created. Note that attr_accessor, a Ruby method, only defines getters and setters for the attributes but does not allow for mass assignment.

Upvotes: 1

Related Questions