如果你正面临着类似的问题,你可能会发现阅读这篇文章很有趣:
- 有人能解释collection_select给我清晰,简单的术语吗?
我试图实现嵌套表单与几个模型和动态添加的collection_select
字段,基于这个伟大的教程https://www.driftingruby.com/episodes/nested-forms-from-scratch
遗憾的是,我目前有麻烦检索产品。Id从我的控制器适当地保存记录。
In my schema:
- 一个配方有许多产品(尽管FormularProducts)有许多订单
- 一个订单有许多OrderProducts(跟踪其数量)和许多Products(跟踪:product_id)
- 一个OrderProduct属于一个Order,属于一个Product
- 一个产品有许多公式,有许多订单,有许多公式产品和有许多订单产品
当我触发一个包含多个OrderProduct记录的提交时,只传递最后一个:product_id:
Started PATCH "/formulars/1/orders/53"
Parameters:
{
"authenticity_token"=>"[FILTERED]",
"product_id"=>{"id"=>"7"}, # <- :product_id of the last collection_select
"order"=>
{
"order_products_attributes"=>
{
"1612773831378"=>{"quantity"=>"1", # <- each OrderProduct dynamically added
"_destroy"=>"false"}, # <-
"1612774917407"=>{"quantity"=>"6", # <- frontend JS substitutes the associated
"_destroy"=>"false"}, # <- objects' :object_id with a unique
"1612774918874"=>{"quantity"=>"4", # <- timestamp.
"_destroy"=>"false"}}}, # <- I need to access :product_id from here,
} # for each OrderProduct added
},
"commit"=>"Modifier ce(tte) Commande",
"formular_id"=>"1",
"id"=>"53" # <- Order's :id
}
字段是如何动态添加到表单的:
# app/views/orders/_form.html.erb
<%= form_with(model: [formular, order] do |form |%> # <- Form for an Order binded to a Formular (nested routes)
....
<%= link_to_add_product_row('Add an article', form, :order_products) %> # <- Call a Helper method
<% end %>
# app/helpers/application_helper.rb
def link_to_add_product_row(name, f, association, **args)
new_object = f.object.send(association).klass.new # <- create a new instance of the associated object
# f.object == #<Order id: 53> in this context
# new_object == #<OrderProduct id: nil, order_id: nil, product_id: nil, quantity: 1>
id = new_object.object_id # <- get its unique :object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize, f: builder) # 'orders/_order_product' is a partial shown below
end
link_to(name, '#', class: "add_fields " + args[:class], data: {id: id, fields: fields.gsub("n",'')})
end
# app/views/orders/_order_product.html.erb
<tr>
#
# I need this collection_select to:
# - display the Product's name
# - display only Products associated to the selected Formular
# - pre-select the Product record, if set
# - return the Product.id to the backend
#
<td><%= collection_select(:product_id, :id, @formular.products, :id, :name) %></td>
<td></td>
<td><%= f.number_field :quantity, hide_label: true %></td>
<td><%= f.submit %></td>
<td>
<%= f.hidden_field :_destroy, as: :hidden, method: :delete %>
<%= link_to 'Delete', '#', class: 'remove_order_product' %>
</td>
</tr>
$(document).on('turbolinks:load', function() {
$('form').on('click', '.add_fields', function(event) {
var regexp, time;
time = new Date().getTime();
regexp = new RegExp($(this).data('id'), 'g');
$('.fields').append($(this).data('fields').replace(regexp, time));
return event.preventDefault();
});
});
# app/controllers/orders_controller.rb
# before_action callback executed on :create and :update
# goal is to retrieve OrderProducts from params, and associate
# them to the current instance of Order
def set_order_products
order_products_params = order_params.dig(:order, :order_products_attributes)
if order_products_params
order_products_params.each_value do |param|
product = Product.find(param['product_id'])
@order.order_products.build(product: product,
quantity: param['quantity'])
end
end
end
# If OrderProducts params were like:
#
# {"TIMESTAMP"=>{
# "product_id"=>"42", # <- this parameter is missing
# "quantity"=>"3",
# "_destroy"=>"false"}}
#
# then I'd be able to identify to which product this OrderProduct is associated to
如果你想要模式代码,请告诉我。
对如何实现这个目标有什么想法吗?我试过添加hidden_fields
,调整collection_select
,使用select
和options_from_collection_for_select
/options_for_select
;但是我必须承认我迷路了(我可能把我的模式过于复杂了)。
TL_DR:如何从Order的控制器内动态生成的field_for(:order_products)
中检索Product的ID ?
From有人可以向我解释collection_select清晰,简单的术语吗?https://stackoverflow.com/a/8908298/11509906
zquares说:
关于使用form_for,同样用非常简单的术语来说,对于form_for中的所有标签,例如:f.t text_field,你不需要提供第一个(object)参数。这是取自form_for语法。
我把collection_select
改成:
<%= collection_select(:product_id, :id, @formular.products, :id, :name) %>
# Parameters: {"authenticity_token"=>"[FILTERED]", "product_id"=>{"id"=>"7"}, "order"=>{"order_products_attributes"=>{"1612782399659"=>{"quantity"=>"3", "_destroy"=>"false"}, "1612782403591"=>{"quantity"=>"5", "_destroy"=>"false"}}}, "commit"=>"Modifier ce(tte) Commande", "formular_id"=>"1", "id"=>"53"}
:
<%= f.collection_select(:product_id, @formular.products, :id, :name) %>
# Parameters: {"authenticity_token"=>"[FILTERED]", "order"=>{"order_products_attributes"=>{"1612782084184"=>{"product_id"=>"3", "quantity"=>"3", "_destroy"=>"false"}, "1612782085172"=>{"product_id"=>"33", "quantity"=>"-3", "_destroy"=>"false"}}}, "commit"=>"Modifier ce(tte) Commande", "formular_id"=>"1", "id"=>"53"}
现在我可以在Order的控制器
中获取相关产品