<%= f.fields_for :products do |products_form| %>
<% @products.each do |product| %>
По сути хелпер "fields_for" уже есть метод перебора, так что тут "each" лишний.
Следовательно строка
<%= f.hidden_field :product_id, value: product.id %>
станет попроще:
<%= products_form.hidden_field :product_id %>
Вообще я бы рекомендовал что-то типа такого:
<%= form_for @order, remote: true do |f| %>
<%= f.fields_for :order_items, @products do |product|
<%= product.hidden_field :product_id %>
<%= product.number_field :quantity, value: 1 %>
<% end %>
<% end %>
Только в модели order не забудьте получить атрибуты дочерней модели - accepts_nested_attributes_for :order_items
В результате в реквесте (кстати, сам реквест должен указывать на контроллер, который будет сохранять модель order) у вас должно быть не просто {"products"=>{"quantity"=>"6", "product_id"=>"2"}}, а что-то типа
{"order_items_attributes"=>[{"quantity"=>"6", "product_id"=>"2"}, {"quantity"=>"3", "product_id"=>"5"}]}