Reputation: 189
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
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