如何通过 Rails 中的嵌套表单传递 account_id
How to pass an account_id through a nested form in Rails
我正在尝试在 rails 中设置一个嵌套表单,并且表单中的父对象和子对象都需要有一个 "Account ID" 以便它们都限定在当前用户的范围内帐户,但我无法弄清楚如何通过嵌套表单为子对象传递当前用户的帐户 ID。我不断收到嵌套对象的验证错误 "Account id must be present"。
父表单是 "Product",我正在尝试将 "Options" 嵌套到 Product.new 表单中。
我正在尝试做这样的事情:
@product.options.account_id = current_user.account.id
但是没用。
这是产品型号:
class Product < ApplicationRecord
belongs_to :account
has_many :options, dependent: :destroy
accepts_nested_attributes_for :options, allow_destroy: true
validates :account_id, presence: true
validates :name, presence: true, length: { maximum: 120 }
end
和选项型号:
class Option < ApplicationRecord
belongs_to :account
belongs_to :product
has_many :option_values, dependent: :destroy
validates :account_id, presence: true
validates :name, presence: true,
length: { maximum: 60 }
end
下面是我如何将 "Options" 嵌套到产品表单中:
<%= form.fields_for :options do |builder| %>
<fieldset class='form-group'>
<%= builder.label :name, 'Add option(s)' %>
<%= builder.text_field :name %>
<small id="optionHelp" class="form-text text-muted">
(e.g. "Sizes" or "Color")
</small>
</fieldset>
<% end %>
这是我的 ProductsController:
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
before_action :restrict_access
def index
@products = Product.where(:account_id => current_user.account.id).all
end
def show
end
def new
@product = Product.new
@product.options.build
end
def edit
end
def create
@account = current_user.account
@product = @account.products.build(product_params)
respond_to do |format|
if @product.save
format.html { redirect_to @product, notice: 'Product was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if @product.update(product_params)
format.html { redirect_to @product, notice: 'Product was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
@product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
end
end
private
def set_product
if Product.find(params[:id]).account_id == current_user.account.id
@product = Product.find(params[:id])
else
redirect_to dashboard_path
end
end
def restrict_access
if index
authorize @products
else
authorize @product
end
end
def product_params
params.require(:product).permit(:account_id, :name,
options_attributes: [:id, :account_id, :name ])
end
end
正确的做法是什么?
最简单的选择是在两种形式中添加一个隐藏字段:
https://apidock.com/rails/ActionView/Helpers/FormHelper/hidden_field
所以在你的情况下,对于选项形式,类似于:
<%= form.fields_for :options do |builder| %>
<fieldset class='form-group'>
<%= builder.label :name, 'Add option(s)' %>
<%= builder.hidden_field :account_id, value: current_account.id %>
<%= builder.text_field :name %>
<small id="optionHelp" class="form-text text-muted">
(e.g. "Sizes" or "Color")
</small>
</fieldset>
<% end %>
这将使您能够访问 [:option][:account_id]
参数,该参数将匹配当前用户的参数。
或者,您可以传递 hidden_field 和 nested_form,如下所示:-
<%= form_for @product do |form|%>
<%= form.fields_for :options do |builder| %>
<fieldset class='form-group'>
<%= builder.label :name, 'Add option(s)' %>
<%= builder.text_field :name %>
<small id="optionHelp" class="form-text text-muted">
(e.g. "Sizes" or "Color")
</small>
<%=builder.hidden_field :account_id, value: current_user.account.id%>
</fieldset>
<% end %>
<%= form.hidden_field :account_id, value: current_user.account.id%>
<%end%>
除此之外,您可以在控制器上设置 account_id
def new
#@product = Product.new
@product = current_user.account.products.new
@product.options.build(account_id: current_user.account.id)
end
我正在尝试在 rails 中设置一个嵌套表单,并且表单中的父对象和子对象都需要有一个 "Account ID" 以便它们都限定在当前用户的范围内帐户,但我无法弄清楚如何通过嵌套表单为子对象传递当前用户的帐户 ID。我不断收到嵌套对象的验证错误 "Account id must be present"。
父表单是 "Product",我正在尝试将 "Options" 嵌套到 Product.new 表单中。
我正在尝试做这样的事情:
@product.options.account_id = current_user.account.id
但是没用。
这是产品型号:
class Product < ApplicationRecord
belongs_to :account
has_many :options, dependent: :destroy
accepts_nested_attributes_for :options, allow_destroy: true
validates :account_id, presence: true
validates :name, presence: true, length: { maximum: 120 }
end
和选项型号:
class Option < ApplicationRecord
belongs_to :account
belongs_to :product
has_many :option_values, dependent: :destroy
validates :account_id, presence: true
validates :name, presence: true,
length: { maximum: 60 }
end
下面是我如何将 "Options" 嵌套到产品表单中:
<%= form.fields_for :options do |builder| %>
<fieldset class='form-group'>
<%= builder.label :name, 'Add option(s)' %>
<%= builder.text_field :name %>
<small id="optionHelp" class="form-text text-muted">
(e.g. "Sizes" or "Color")
</small>
</fieldset>
<% end %>
这是我的 ProductsController:
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
before_action :restrict_access
def index
@products = Product.where(:account_id => current_user.account.id).all
end
def show
end
def new
@product = Product.new
@product.options.build
end
def edit
end
def create
@account = current_user.account
@product = @account.products.build(product_params)
respond_to do |format|
if @product.save
format.html { redirect_to @product, notice: 'Product was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if @product.update(product_params)
format.html { redirect_to @product, notice: 'Product was successfully updated.' }
else
format.html { render :edit }
end
end
end
def destroy
@product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
end
end
private
def set_product
if Product.find(params[:id]).account_id == current_user.account.id
@product = Product.find(params[:id])
else
redirect_to dashboard_path
end
end
def restrict_access
if index
authorize @products
else
authorize @product
end
end
def product_params
params.require(:product).permit(:account_id, :name,
options_attributes: [:id, :account_id, :name ])
end
end
正确的做法是什么?
最简单的选择是在两种形式中添加一个隐藏字段:
https://apidock.com/rails/ActionView/Helpers/FormHelper/hidden_field
所以在你的情况下,对于选项形式,类似于:
<%= form.fields_for :options do |builder| %>
<fieldset class='form-group'>
<%= builder.label :name, 'Add option(s)' %>
<%= builder.hidden_field :account_id, value: current_account.id %>
<%= builder.text_field :name %>
<small id="optionHelp" class="form-text text-muted">
(e.g. "Sizes" or "Color")
</small>
</fieldset>
<% end %>
这将使您能够访问 [:option][:account_id]
参数,该参数将匹配当前用户的参数。
或者,您可以传递 hidden_field 和 nested_form,如下所示:-
<%= form_for @product do |form|%>
<%= form.fields_for :options do |builder| %>
<fieldset class='form-group'>
<%= builder.label :name, 'Add option(s)' %>
<%= builder.text_field :name %>
<small id="optionHelp" class="form-text text-muted">
(e.g. "Sizes" or "Color")
</small>
<%=builder.hidden_field :account_id, value: current_user.account.id%>
</fieldset>
<% end %>
<%= form.hidden_field :account_id, value: current_user.account.id%>
<%end%>
除此之外,您可以在控制器上设置 account_id
def new
#@product = Product.new
@product = current_user.account.products.new
@product.options.build(account_id: current_user.account.id)
end