0
votes

I'm getting this error:

Can't mass-assign protected attributes: quantities

I looked up all the threads concerning this issue in the site, but couldn't find something to answer my problem. Here are the code snippets:

product.rb

class Product < ActiveRecord::Base
  attr_accessible :name, :quantities_attributes
  has_many :quantities

  accepts_nested_attributes_for :quantities, :allow_destroy => :true,
  :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }

new.html.erb

<% if @was_submitted %>
  <%= form_for(:new_product_array, :url => products_path) do |f| %>
    <% prefix ||= 0 %>
    <% @new_product_array.each do |n| %>
      <% n.quantities.build %>
      <% prefix += 1 %>
      <%= f.fields_for(prefix.to_s ) do |child| %>
        <div class="field">
          <%= child.label :name %><br />
          <%= child.text_field :name%>
        </div>
        <%= render :partial => 'quantities/form',
                   :locals => {:form => child} %>
      <% end %>
    <% end %>
    <div class="actions">
      <%= submit_tag :submit %>
    </div>
  <% end %>
<% else %>
  <%= form_tag new_product_path, :method => 'get' do %>
  <p align=center>
    How many Items are you Adding? (1-100)
    <%= number_field_tag 'amount', 1, :in => 1...100 %>
    </br>
    To which storage?
    <%= number_field_tag 'storage', 1, :in => 1...100 %>
    <%= submit_tag "Next", :name => 'submitted' %>
  </p>
  <% end %>
<% end %>
<%= link_to 'Back', products_path %>

product_controller.rb

def new
  @product = Product.new

  if params['submitted'] 
    @was_submitted = true
    @amount_form = params['amount']
    @new_product_array = []
    (1..@amount_form.to_i).each do
      @new_product_array << Product.new
    end
    @storage_form = params['storage']
  else
    @was_submitted = false
  end

  respond_to do |format|
    format.html # new.html.erb
    format.json { render :json => @product }
  end
end

def create
  i=0
  logger.info params[:new_product_array].inspect
  params[:new_product_array].each do |new_product|
    if new_product.last[:name] != nil
      @new_product_array[i] = Product.new(new_product.last)
      @new_product_array[i].save
      i+=1
    end
  end
  redirect_to(products_path)
end

quantity.rb

class Quantity < ActiveRecord::Base
  belongs_to :product
  attr_accessible :amount, :storage
end

quantity/_form.html.erb

<%= form.fields_for :quantities do |quant| %>
  <div class="field">
    <%= quant.label :storage %><br />
    <%= quant.number_field :storage %>
  </div>
  <div class="field">
    <%= quant.label :amount %><br />
    <%= quant.number_field :amount %>
  </div>
  <% unless quant.object.nil? || quant.object.new_record? %>
    <div class="field">
      <%= quant.label :_destroy, 'Remove:' %>
      <%= quant.check_box :_destroy %>
    </div>
  <% end %>
<% end %>

Overall what Im trying to do, is ask the user how much products to add, then make a form with the number of fields the user specifies and with one submit button add all of the products, whereas when you add a product you also add a quantity record which holds more information on the product.

2
Is '@was_submitted' there to tell if you are loading new.html.erb? That new controller looks really ugly! - Noah Clark
Stop what you're doing and read this book railsantipatterns.com - Peter Brown
I'd also recommend Rails 3 in Action! - Noah Clark
thanks for the tips guys, will start reading that - Yarneo

2 Answers

1
votes

You need a line like this:

attr_accessible :name, :quantities_attributes, :quantities
0
votes

You have very bad code, it can be much simplier 100%.

Your problem is that form dont' know nothing about your resource (product), so it can't render 'smartly' fields "quantities_attributes", it renders "quantities" instead.