ruby-on-rails - 重复表单字段并更新到数据库
问题描述
任何帮助将不胜感激,我对 Rails 相当陌生。
我有两个模型一个购物清单和一个产品。我想一次将多个产品保存/更新到购物清单。
建议的更改不会更新模型。我一直在谷歌搜索,答案是“attr_accessor”还是 find_or_create_by?
尝试 1 - 现有代码
错误
> unknown attribute 'products_attributes' for Product.
Request
Parameters:
{"_method"=>"patch",
"authenticity_token"=>"3BgTQth38d5ykd3EHiuV1hkUqBZaTmedaJai3p9AR1N2bPlHraVANaxxe5lQYaVcWNoydA3Hb3ooMZxx15YnOQ==",
"list"=>
{"products_attributes"=>
{"0"=>{"title"=>"ten", "id"=>"12"},
"1"=>{"title"=>"two", "id"=>"13"},
"2"=>{"title"=>"three", "id"=>"14"},
"3"=>{"title"=>"four", "id"=>"15"},
"4"=>{"title"=>"five", "id"=>"16"},
"5"=>{"title"=>""},
"6"=>{"title"=>""},
"7"=>{"title"=>""},
"8"=>{"title"=>""},
"9"=>{"title"=>""},
"10"=>{"title"=>""}}},
"commit"=>"Save Products",
"id"=>"7"}
尝试 2 - 页面重新加载没有错误,并且没有更新任何预期的字段。认真地,我正在谷歌搜索并复制和粘贴代码片段,但徒劳地希望解锁正确的组合。添加到产品模式
class Product < ApplicationRecord
attr_accessor :products_attributes
belongs_to :list, optional: true
end
<%= content_tag(:h1, 'Add Products To This List') %>
<%= form_for(@list) do |f| %>
<%= f.fields_for :products do |pf| %>
<%= pf.text_field :title %><br>
<% end %>
<p>
<%= submit_tag "Save Products" %>
</p>
<% end %>
<%= link_to "Back To List", lists_path %>
列表控制器
def update
#render plain: params[:list].inspect
@list = List.find(params[:id])
if @list.products.update(params.require(:list).permit(:id, products_attributes: [:id, :title]))
redirect_to list_path(@list)
else
render 'show'
end
列表模型
class List < ApplicationRecord
has_many :products
accepts_nested_attributes_for :products
end
原创无所事事——产品模型
class Product < ApplicationRecord
belongs_to :list, optional: true
end
解决方案
如果您只希望用户能够选择产品并将它们放在列表中,则需要多对多关联:
class List < ApplicationRecord
has_many :list_items
has_many :products, through: :list_products
end
class ListItem < ApplicationRecord
belongs_to :list
belongs_to :product
end
class Product < ApplicationRecord
has_many :list_items
has_many :lists, through: :list_products
end
这避免了在 products 表上创建大量重复项,称为规范化。
然后,您可以通过简单地使用选择来选择现有产品:
<%= form_for(@list) do |f| %>
<%= f.label :product_ids %>
<%= f.collection_select(:product_ids, Product.all, :name, :id) %>
# ...
<% end %>
请注意,这与嵌套路由或嵌套属性无关。它只是一个使用product_ids
关联创建的设置器的选择。此表格仍将提交至/lists
或/lists/:id
您可以通过以下方式将一组 id 列入白名单:
def list_params
params.require(:list)
.permit(:foo, :bar, product_ids: [])
end
要以一种形式添加创建/更新/删除一堆嵌套记录,您可以accepts_nested_attributes_for
使用fields_for
:
class List < ApplicationRecord
has_many :list_items
has_many :products, through: :list_products
accepts_nested_attributes_for :products
end
<%= form_for(@list) do |f| %>
<%= form.fields_for :products do |pf| %>
<%= pf.label :title %><br>
<%= pf.text_field :title %>
<% end %>
# ...
<% end %>
如果您不使用记录播种关联,当然fields_for
不会显示任何内容。那就是你完全放错地方的那个循环进来的地方。
class ListsController < ApplicationController
# ...
def new
@list = List.new
5.times { @list.products.new } # seeds the form
end
def edit
@list = List.find(params[:id])
5.times { @list.products.new } # seeds the form
end
# ...
def update
@list = List.find(params[:id])
if @list.update(list_params)
redirect_to @list
else
render :new
end
end
private
def list_params
params.require(:list)
.permit(
:foo, :bar,
product_ids: [],
products_attrbutes: [ :title ]
)
end
end
必读:
推荐阅读
- python - 使用 Locust 对 Asp.net Core SignalR 进行负载测试
- c++ - Cmake:pkg_check_modules错误:包'...','virtual:world'需要,找不到
- .net-core - 是否可以确定 Thrift TBaseClient 当前是否忙碌或可用?
- macos - macOS 的 VoiceOver:如何为视图控制器设置最初聚焦的元素?
- eclipse - Eclipse Checkstyle 插件 8.41.0 不会运行
- python - 模板中的 Django 重置循环
- java - 使 Y 轴相对于旋转 30 度的 X 轴移动
- apache-spark - 使用 Spark 结构化流从许多不同的 kafka 代理中消费相同主题的最佳方式是什么?
- android - 有没有办法将覆盖函数放在 Kotlin 的单独文件中?
- json - 在 Power Automate 中,如何从 .csv 电子邮件附件中获取数据并将其格式化以供显示?