I am using Rails 5.2 and building an ecomm site.
My new.html.erb
page has a simple_form with a combination of Product
fields as well as other params which are handled outside the strong params and the creation of the new instance.
One of the features of the form is a eventListener
which creates the :sku
automatically based on four input values. The product number, the sku and the live status are hidden.
Here is the simplified version of the html.erb
:
<%= simple_form_for @new_product do |f| %>
<%= f.error_notification %>
<%= f.input :name%>
<%= f.association :size, collection: @all_sizes.map{ |s| [s.name, s.id, {'data-code-num' => s.code_num}]}, input_html:{class: 'sku-suffix-component'} %>
<%= f.association :color, collection: @all_colors.map{ |s| [s.name, s.id, {'data-code-num' => s.code_num}]}, input_html:{class: 'sku-suffix-component'} %>
<%= f.association :pattern, collection: @all_patterns.map{ |s| [s.name, s.id, {'data-code-num' => s.code_num}]}, input_html:{class: 'sku-suffix-component'} %>
<%= f.input :product_number, as: :hidden, input_html:{ value: @new_product.product_number, class: "sku-suffix-component" } %>
<%= f.input :sku,as: :hidden, html:{id: "new-product-form-sku-input"} %>
<%= f.input :live_status, as: :hidden, :input_html => { :value => @new_product.live_status } %>
<%= f.input :description, as: :text %>
<%= f.association :brand%>
<%= f.association :style %>
<%= f.input :price %>
<%= f.input :quantity, input_html:{value: 1}%>
<%= f.association :segment %>
<%= f.association :main_category %>
<%= f.association :category %>
<%= f.association :country, class: '' %>
<!-- Here are some inputs for adding records to a material join table -->
<!-- And the names of the inputs are dynamically created -->
<% 5.times.with_index do |_, i| %>
<% num = i + 1 %>
<label class="form-control-label integer" for="material_percent_id_<%= num < 10 ? "0" + num.to_s : num.to_s %>">Percent</label>
<input class="form-control numeric integer required" type="number" step="1" name="material_percent_<%= num < 10 ? "0" + num.to_s : num.to_s %>" id="material_percent_id_<%= num < 10 ? "0" + num.to_s : num.to_s %>">
<label class="form-control-label select" for="material_id_id_<%= num < 10 ? "0" + num.to_s : num.to_s %>">Material Component #<%= num %> </label>
<select class="form-control select" name="material_id_<%= num < 10 ? "0" + num.to_s : num.to_s %>" id="material_id_id_<%= num < 10 ? "0" + num.to_s : num.to_s %>">
<option value=""></option>
<% @all_materials.each do |material| %>
<option value="<%= material.id %>"><%= material.name %></option>
<% end %>
</select>
<% end %>
<!-- Here are some inputs for adding multiple photos to the products using active_storage -->
<% (1..8).each do |i| %>
<%= f.label "Photo [#{i}]" %>
<%= f.file_field :photos, multiple: true %>
<% end %>
<%= f.button :submit %>
<% end %>
Creating new products using this simple_form
works fine, along with instances in the join table, through the create method
, shown here:
def create
@all_sizes = Size.all
@all_colors = Color.all
@all_patterns = Pattern.all
@new_product = Product.new(product_params)
@all_materials = Material.all
if @new_product.save
5.times.with_index do |_, i|
if params["material_id_0#{(i + 1)}"] != ""
ProductMaterial.create!(product_id: @new_product.id,
material_id: params["material_id_0#{(i + 1)}"].to_i,
percent: params["material_percent_0#{(i + 1)}"].to_i)
else
break
end
end
redirect_to @new_product
else
render :new
end
end
Using nearly the exact same form (some code added to dynamically render the join table inputs and the photos inputs correctly), but all inputs present; and using the exact same strong params in the controller; going through the update
method in the controller produces an argument error. Here is the update
method:
def update
@product = Product.find(params[:id])
@product = Product.update(product_params) # here is where the error happens
@all_sizes = Size.all
@all_colors = Color.all
@all_patterns = Pattern.all
@all_materials = Material.all
if @product.save
5.times.with_index do |_, i|
if params["material_id_0#{(i + 1)}"] != ""
ProductMaterial.create!(product_id: @product.id,
material_id: params["material_id_0#{(i + 1)}"].to_i,
percent: params["material_percent_0#{(i + 1)}"].to_i)
else
break
end
end
redirect_to @product
else
render :edit
end
end
Here is the exact syntax of the error as seen in the server:
ArgumentError (wrong number of arguments (given 1, expected 2)):
app/controllers/products_controller.rb:72:in `update'
Here
@product = Product.update(product_params)
you're trying to call instance method update
on the Product class itself. new
is a class method, so it works good in create action. How it should be:
def update
@product = Product.find(params[:id])
# here you define different @all instances
# you don't need to update and save separately, because instance is saved already
# if you call update on it and update goes well
if @product.update(product_params)
# here goes the rest controller code