2

Hello I have 2 models Product and ProductSize. I create a ProductSize in an Product form.

Problem is, its not persisting creating the ProductSizes. You should be able to go product.product_sizes and a list of ProductSizes show.

product.rb

class Product < ActiveRecord::Base
  acts_as_taggable

  belongs_to :user
  belongs_to :category

  has_many :product_sizes
  has_many :product_images, :dependent => :destroy

  validates :title, presence: true, length: { maximum: 30 }
  validates :description, presence: true, length: { maximum: 2000 }
  validates :category, :user, :price, presence: true

  accepts_nested_attributes_for :product_images, :product_sizes, allow_destroy: true
end

product_size.rb

class ProductSize < ActiveRecord::Base
  belongs_to :product
  belongs_to :size

  validates :quantity, presence: true
end

Here is my form. The way it works is: User can upload images, then select what category the Product is for. Lets say they select Shirt, then a list of all shirt sizes will drop down like XS, Small, Medium, Large. Then the user puts what quantity they have for the sizes they have. Like 13 XS shirts and 4 large Shirts.

<%= javascript_include_tag "custom" %>
<div class="container">
  <div class=“row”>
    <div class="col-md-6 col-md-offset-3">
      <div class="panel panel-primary">
        <div class="panel-body">
          <%= simple_nested_form_for @product do |f| %>
            <%= f.fields_for :product_images do |product_image| %>
              <% if product_image.object.new_record? %>
                <%= product_image.file_field(:product_image) %>
                <%= product_image.link_to_remove "Remove Image", data: { confirm: "Are you sure you want to delete this image?" } %>
              <% else %>
                <%= product_image.hidden_field :_destroy %>
              <% end %>
            <% end %>
            <p><%= f.link_to_add "Add a image", :product_images, :data => { :product_image => "#product_images" } %></p>
            <%= f.collection_select :category_id, @categories, :id, :name, include_blank: true, prompt: "Select One Category" %>

            <% @categories.each do |category| %>
              <div class='sizes_container' id ='sizes_container_for_<%= category.id %>'>
                <% category.sizes.each do |size| %>
                  <%= label_tag "product_form[sizes_by_id][#{size.id}]", size.title %>
                  <%= text_field_tag "product_sizes_attributes[sizes_quantity][#{size.id}]" %>
                <% end %>
              </div>
            <% end %>

            <%= f.input :title, label:"Title"%>
            <%= f.input :price, label:"Price"%>
            <%= f.input :description,label:"Description" %>
            <%= f.input :size_description, label:"Size Details"%>
            <%= f.input :shipping_description, label:"Shipping Details"%>
            <%= f.input :tag_list,label:"Tags - Seperate tags using comma ','. 5 tags allowed per product" %>
            <%= f.button :submit, "Create new product", class: "btn-lg btn-success" %>
          <% end %>
        </div>
      </div>
    </div>
  </div>
</div>

Here are what my params look like at the create action.

    36: def create
 => 37:   binding.pry
    38:   @product = Product.new product_params
    39:   @product.user_id = current_user.id
    40:   if @product.save
    41:     redirect_to @product
    42:     flash[:success] = "You have created a new product"
    43:   else
    44:     flash[:danger] = "Your product didn't save"
    45:     render "new"
    46:   end
    47: end

**[1] pry(#<ProductsController>)> product_params**
=> {"title"=>"test",
 "price"=>"3325",
 "description"=>"test",
 "tag_list"=>"test",
 "category_id"=>"3",
 "size_description"=>"test",
 "shipping_description"=>"test",
 "product_images_attributes"=>
  {"0"=>
    {"product_image"=>
      #<ActionDispatch::Http::UploadedFile:0x007f8cb786a010
       @content_type="image/jpeg",
       @headers="Content-Disposition: form-data; name=\"product[product_images_attributes][0][product_image]\"; filename=\"780069_black_l.jpg\"\r\nContent-Type: image/jpeg\r\n",
       @original_filename="780069_black_l.jpg",
       @tempfile=#<File:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151223-46388-p07o84.jpg>>,
     "_destroy"=>"false"},
   "1450863732810"=>
    {"product_image"=>
      #<ActionDispatch::Http::UploadedFile:0x007f8cb7869e08
       @content_type="image/jpeg",
       @headers="Content-Disposition: form-data; name=\"product[product_images_attributes][1450863732810][product_image]\"; filename=\"20090a.jpg\"\r\nContent-Type: image/jpeg\r\n",
       @original_filename="20090a.jpg",
       @tempfile=#<File:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151223-46388-n9mzf2.jpg>>,
     "_destroy"=>"false"}}}

[2] pry(#<ProductsController>)> params
=> {"utf8"=>"✓",
 "authenticity_token"=>"jfh6vsb1N1zhAIFyzer4liwuV+iHQ+P8pF6mZHUyF8IXNn6oXqnLDse84jnrP3BKI889CWigIDqVMJncxOYZ9Q==",
 "product"=>
  {"product_images_attributes"=>
    {"0"=>
      {"product_image"=>
        #<ActionDispatch::Http::UploadedFile:0x007f8cb786a010
         @content_type="image/jpeg",
         @headers="Content-Disposition: form-data; name=\"product[product_images_attributes][0][product_image]\"; filename=\"780069_black_l.jpg\"\r\nContent-Type: image/jpeg\r\n",
         @original_filename="780069_black_l.jpg",
         @tempfile=#<File:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151223-46388-p07o84.jpg>>,
       "_destroy"=>"false"},
     "1450863732810"=>
      {"product_image"=>
        #<ActionDispatch::Http::UploadedFile:0x007f8cb7869e08
         @content_type="image/jpeg",
         @headers="Content-Disposition: form-data; name=\"product[product_images_attributes][1450863732810][product_image]\"; filename=\"20090a.jpg\"\r\nContent-Type: image/jpeg\r\n",
         @original_filename="20090a.jpg",
         @tempfile=#<File:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151223-46388-n9mzf2.jpg>>,
       "_destroy"=>"false"}},
   "category_id"=>"3",
   "title"=>"test",
   "price"=>"3325",
   "description"=>"test",
   "size_description"=>"test",
   "shipping_description"=>"test",
   "tag_list"=>"test"},
 "product_sizes_attributes"=>{"sizes_quantity"=>{"1"=>"3", "2"=>"4", "3"=>""}},
 "commit"=>"Create new product",
 "controller"=>"products",
 "action"=>"create"}

[3] pry(#<ProductsController>)> params[:product_sizes_attributes]
=> {"sizes_quantity"=>{"1"=>"3", "2"=>"4", "3"=>""}}
1
  • i know it has someting to do with my params. product_params doesn't have the product_sizes_attributes in it. I don't know how to add it. Commented Dec 23, 2015 at 10:12

2 Answers 2

1

Looks like your form doesn't have the fields_for for the product_sizes:

<%= simple_nested_form_for @product do |f| %>
   <%= f.fields_for :product_sizes do |product_size| %>
       <%= product_size.text_field .... %>
   <% end %>
<% end %>

This will have to be backed up with the appropriate controller code:

#app/controllers/products_controller.rb
class ProductsController < ApplicationController
   def new
      @product = Product.new
      @product.product_images.build
      @product.product_sizes.build
   end

   def create
      @product = Product.new product_params
      @product.save
   end

   private

   def product_params
      params.require(:product).permit(:x, :y, :z, product_images_attributes: [:image], product_sizes_attributes: [...])
   end
end

This should get it working for you.

Sign up to request clarification or add additional context in comments.

5 Comments

Hello Rich. Thanks for your reply. In the do know what you're suggesting with the form however i don't think it applies to my form. Take a look at my form where it starts with this<% @categories.each do |category| %>. Few lines below that i have my product_sizes.
I don't see where you have them? If you want to create a nested object, you have to call fields_for
Lets say the user Chooses Shirts as the category a list of shirt sizes will drop down like XS, Small, Medium, Large. Besides each of the sizes is a quantity field so the user can input how many they have. I will see if i can get it to work with fields_for
Pretty simple really, just have a collection_select with the sizes and a fields_for to allow them to add a size
Sorry i was on holiday. Its all working now and thank you again.
0

Use fields_for for project_size. Get the total @sizes from @categories and use collection_select like you have used previously. Your project_size form code

<% @categories.each do |category| %>
   <div class='sizes_container' id ='sizes_container_for_<%= category.id %>'>
   <% category.sizes.each do |size| %>
     <%= label_tag "Size"product_form[sizes_by_id][#{size.id}]", size.title %>
     <%= text_field_tag "product_sizes_attributes[sizes_quantity][#{size.id}]" %>
   <% end %>
   </div>
<% end %>

will be

<% @sizes = Size.joins(:category).where('categories.id IN (?)', @categories.map(&:id)) %>

<%= f.fields_for :product_sizes do |product_size| %>
   <%= label_tag "Size" %>
   <%= product_size.collection_select :size_id, @sizes, :id, :title, include_blank: true, prompt: "Select One Size" %>
   <%= product_size.text_field :quantity %>
<% end %>

And product_params will be

params.require(:product).permit(:title, :price, :description, :tag_list,:category_id, :size_description, :shipping_description, product_images_attributes: [:id, product_image: [] ], product_sizes_attributes: [:id, :size_id, :quantity])

I hope this would be helpful.

2 Comments

Hello do i need to change this code in the form<%= text_field_tag "product_sizes_attributes[sizes_quantity][#{size.id}]" %> to get this to work?
Don't need to create fields as you mentioned above. You should use fields_for. Let me update the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.