嵌套 fields_for 表单不会创建子对象 rails 5
Nested fields_for form wont create child objects rails 5
sale.rb "Parent"
class Sale < ActiveRecord::Base
has_many :branch_history_solds
accepts_nested_attributes_for :branch_history_solds, :reject_if => lambda { |a| a[:content].blank? },
:allow_destroy => true
end
class SalesController < ApplicationController
before_action :set_sale, only: [:show, :edit, :update, :destroy]
# GET /sales
# GET /sales.json
def index
@sales = Sale.all
end
# GET /sales/1
# GET /sales/1.json
def show
end
# GET /sales/new
def new
@sale = Sale.new
@sale.branch_history_solds.build
end
# GET /sales/1/edit
def edit
end
# POST /sales
# POST /sales.json
def create
@sale = Sale.create(sale_params)
# @sale.branch_history_solds.build
respond_to do |format|
if @sale.save
format.html { redirect_to @sale, notice: 'Sale was successfully created.' }
format.json { render :show, status: :created, location: @sale }
else
format.html { render :new }
format.json { render json: @sale.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /sales/1
# PATCH/PUT /sales/1.json
def update
@sale = Sale.find(params[:id])
respond_to do |format|
if @sale.update_attributes(sale_params)
format.html { redirect_to @sale, notice: 'Sale was successfully updated.' }
format.json { render :show, status: :ok, location: @sale }
else
format.html { render :edit }
format.json { render json: @sale.errors, status: :unprocessable_entity }
end
end
end
# DELETE /sales/1
# DELETE /sales/1.json
def destroy
@sale.destroy
respond_to do |format|
format.html { redirect_to sales_url, notice: 'Sale was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_sale
@sale = Sale.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def sale_params
params.require(:sale).permit(:receipt_no, :customer_name, :phone_number, :email, :branch_id, :paid, branch_history_sold_attributes: [:id, :sold, :branch_product_id])
end
end
branch_history_sold.rb "Child"
class BranchHistorySold < ActiveRecord::Base
belongs_to :sale
end
class BranchHistorySoldsController < ApplicationController
def index
@search = BranchHistorySold.ransack(params[:q])
@branch_sold_histories = @search.result(distinct: true).group(:name).sum(:sold)
end
def create
@sale = Sale.find(params[:sale_id]) # Find specific branch_product we will be working with
@branch_history_sold = @sale.branch_history_solds.create(branch_history_sold_params) # Enable whitelisted attributes to get created
flash[:notice] = "New products have been Sold from branch" # flash notice will show immediately after branch_history_sold gets created
redirect_to branch_product_path(@branch_product) # redirect to branch_product show page
end
def destroy
@sale = Sale.find(params[:sale_id]) # Find specific branch_product we will be working with
@branch_history_sold = @sale.branch_history_solds.find(params[:id]) # Find specific branch_history_sold that will be destroyed
@branch_history_sold.destroy # destroy branch_history_sold
flash[:notice] = "Newly sold products have been added back to branch" # flash notice will show immediately after branch_history_sold is destroyed
redirect_to branch_product_path(@branch_product) # redirect to branch_product show page
end
private
def branch_history_sold_params
params.require(:branch_history_sold).permit(:sold, :customer_name) # whitelisted attributes
end
end
最后是带有 fields_for 属性的表单
<div class="container">
<div class="row">
<%= form_for @sale, html: { class: "form-horizontal" } do |f| %>
<!-- Text input-->
<div class="form-group">
<label class="col-md-1 control-label">R/NO</label>
<div class="col-md-6">
<%= f.collection_select(:branch_id, Branch.all, :id, :name) %>
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-1 control-label">R/NO</label>
<div class="col-md-6">
<%= f.text_field :receipt_no, placeholder: "Receipt number", class: "form-control input-md" %>
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-1 control-label" >Name</label>
<div class="col-md-6">
<%= f.text_field :customer_name, placeholder: "Prince Abalogu", class: "form-control input-md" %>
</div>
</div>
<!-- Appended Input-->
<div class="form-group">
<label class="col-md-1 control-label">Number</label>
<div class="col-md-6">
<%= f.text_field :phone_number, placeholder: "08185438075", class: "form-control input-md" %>
</div>
</div>
<!-- Appended Input-->
<div class="form-group">
<label class="col-md-1 control-label">E-mail</label>
<div class="col-md-6">
<%= f.text_field :email, placeholder: "example@yahoo.com", class: "form-control input-md" %>
</div>
</div>
<!-- Appended Input-->
<%= f.fields_for :branch_history_solds, @sale.branch_history_solds.build do |b| %>
<div class="form-group">
<label class="col-md-1 control-label">Product</label>
<div class="col-md-6">
<%= b.number_field :sold, placeholder: "Quantity" %>
</div>
</div>
<div class="form-group">
<label class="col-md-1 control-label"></label>
<div class="col-md-6">
<% @branch = BranchProduct.where :branch_id, 19 %>
<%= b.collection_select(:branch_product_id, BranchProduct.where(branch_id: params[:branch_id] ), :id, :name ) %> Select Product
</div>
</div>
<% end %>
<!-- Appended Input-->
<div class="form-group">
<label class="col-md-1 control-label"></label>
<div class="col-md-6">
<%= f.check_box :paid %> Paid
</div>
</div>
<!-- Button (Double) -->
<div class="form-group">
<label class="col-md-1 control-label"></label>
<div class="col-md-8">
<%= f.button :submit %>
</div>
</div>
<% end %>
</div>
</div>
表格显示了,但我现在遇到的唯一问题是在我提交后它没有创建任何 branch_history_solds
问题是您用来评估是否应拒绝嵌套记录的 lambda 将始终 return 为真,因为您的 form/model 没有 content
属性:
class Sale < ActiveRecord::Base
has_many :branch_history_solds
accepts_nested_attributes_for :branch_history_solds, :reject_if => lambda { |a| a[:content].blank? },
:allow_destroy => true
end
您还将错误的属性列入白名单 branch_history_sold
而不是 branch_history_solds
。
您需要将其更改为实际传递的属性:
class Sale < ActiveRecord::Base
has_many :branch_history_solds
accepts_nested_attributes_for :branch_history_solds, :reject_if => lambda { |a| a[:branch_product_id].blank? },
:allow_destroy => true
end
但是你的一般设置很奇怪,我不知道它是否只是命名但它没有多大意义。
如果您想创建一个销售点系统或订单管理系统,您可以这样做:
class Order
belongs_to :customer
has_many :line_items
has_many :products, through: :line_items
accepts_nested_attributes_for :line_items,
allow_destroy: true,
reject_if: -> { |li| li[:product_id].blank? || li[:quantity].blank? }
end
# columns:
# - order_id [integer, index, foreign key]
# - product_id [integer, index, foreign key]
# - quantity [decimal or integer]
# - price [decimal]
# - subtotal [decimal]
class LineItem
belongs_to :order
belongs_to :product
end
class Product
has_many :line_items
has_many :orders, through: :line_items
end
class OrdersController
def new
end
def create
@order = Order.new(order_params) do
order.customer = current_user
end
if (@order.save)
else
end
end
private
def order_params
params.require(:order)
.permit(:foo, :bar, line_item_attributes: [:product_id, :quantity])
end
end
请注意,您应该只让用户传递数量极其有限的参数 - 永远不要从用户那里获取价格之类的东西。实际的定价逻辑应该在模型层完成。您也不想从订单模型中分离客户详细信息 - 否则每个重复订单都会重复数据。在添加其他功能(如搜索)之前,我会花一些时间了解实际的领域模型。
sale.rb "Parent"
class Sale < ActiveRecord::Base
has_many :branch_history_solds
accepts_nested_attributes_for :branch_history_solds, :reject_if => lambda { |a| a[:content].blank? },
:allow_destroy => true
end
class SalesController < ApplicationController
before_action :set_sale, only: [:show, :edit, :update, :destroy]
# GET /sales
# GET /sales.json
def index
@sales = Sale.all
end
# GET /sales/1
# GET /sales/1.json
def show
end
# GET /sales/new
def new
@sale = Sale.new
@sale.branch_history_solds.build
end
# GET /sales/1/edit
def edit
end
# POST /sales
# POST /sales.json
def create
@sale = Sale.create(sale_params)
# @sale.branch_history_solds.build
respond_to do |format|
if @sale.save
format.html { redirect_to @sale, notice: 'Sale was successfully created.' }
format.json { render :show, status: :created, location: @sale }
else
format.html { render :new }
format.json { render json: @sale.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /sales/1
# PATCH/PUT /sales/1.json
def update
@sale = Sale.find(params[:id])
respond_to do |format|
if @sale.update_attributes(sale_params)
format.html { redirect_to @sale, notice: 'Sale was successfully updated.' }
format.json { render :show, status: :ok, location: @sale }
else
format.html { render :edit }
format.json { render json: @sale.errors, status: :unprocessable_entity }
end
end
end
# DELETE /sales/1
# DELETE /sales/1.json
def destroy
@sale.destroy
respond_to do |format|
format.html { redirect_to sales_url, notice: 'Sale was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_sale
@sale = Sale.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def sale_params
params.require(:sale).permit(:receipt_no, :customer_name, :phone_number, :email, :branch_id, :paid, branch_history_sold_attributes: [:id, :sold, :branch_product_id])
end
end
branch_history_sold.rb "Child"
class BranchHistorySold < ActiveRecord::Base
belongs_to :sale
end
class BranchHistorySoldsController < ApplicationController
def index
@search = BranchHistorySold.ransack(params[:q])
@branch_sold_histories = @search.result(distinct: true).group(:name).sum(:sold)
end
def create
@sale = Sale.find(params[:sale_id]) # Find specific branch_product we will be working with
@branch_history_sold = @sale.branch_history_solds.create(branch_history_sold_params) # Enable whitelisted attributes to get created
flash[:notice] = "New products have been Sold from branch" # flash notice will show immediately after branch_history_sold gets created
redirect_to branch_product_path(@branch_product) # redirect to branch_product show page
end
def destroy
@sale = Sale.find(params[:sale_id]) # Find specific branch_product we will be working with
@branch_history_sold = @sale.branch_history_solds.find(params[:id]) # Find specific branch_history_sold that will be destroyed
@branch_history_sold.destroy # destroy branch_history_sold
flash[:notice] = "Newly sold products have been added back to branch" # flash notice will show immediately after branch_history_sold is destroyed
redirect_to branch_product_path(@branch_product) # redirect to branch_product show page
end
private
def branch_history_sold_params
params.require(:branch_history_sold).permit(:sold, :customer_name) # whitelisted attributes
end
end
最后是带有 fields_for 属性的表单
<div class="container">
<div class="row">
<%= form_for @sale, html: { class: "form-horizontal" } do |f| %>
<!-- Text input-->
<div class="form-group">
<label class="col-md-1 control-label">R/NO</label>
<div class="col-md-6">
<%= f.collection_select(:branch_id, Branch.all, :id, :name) %>
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-1 control-label">R/NO</label>
<div class="col-md-6">
<%= f.text_field :receipt_no, placeholder: "Receipt number", class: "form-control input-md" %>
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-1 control-label" >Name</label>
<div class="col-md-6">
<%= f.text_field :customer_name, placeholder: "Prince Abalogu", class: "form-control input-md" %>
</div>
</div>
<!-- Appended Input-->
<div class="form-group">
<label class="col-md-1 control-label">Number</label>
<div class="col-md-6">
<%= f.text_field :phone_number, placeholder: "08185438075", class: "form-control input-md" %>
</div>
</div>
<!-- Appended Input-->
<div class="form-group">
<label class="col-md-1 control-label">E-mail</label>
<div class="col-md-6">
<%= f.text_field :email, placeholder: "example@yahoo.com", class: "form-control input-md" %>
</div>
</div>
<!-- Appended Input-->
<%= f.fields_for :branch_history_solds, @sale.branch_history_solds.build do |b| %>
<div class="form-group">
<label class="col-md-1 control-label">Product</label>
<div class="col-md-6">
<%= b.number_field :sold, placeholder: "Quantity" %>
</div>
</div>
<div class="form-group">
<label class="col-md-1 control-label"></label>
<div class="col-md-6">
<% @branch = BranchProduct.where :branch_id, 19 %>
<%= b.collection_select(:branch_product_id, BranchProduct.where(branch_id: params[:branch_id] ), :id, :name ) %> Select Product
</div>
</div>
<% end %>
<!-- Appended Input-->
<div class="form-group">
<label class="col-md-1 control-label"></label>
<div class="col-md-6">
<%= f.check_box :paid %> Paid
</div>
</div>
<!-- Button (Double) -->
<div class="form-group">
<label class="col-md-1 control-label"></label>
<div class="col-md-8">
<%= f.button :submit %>
</div>
</div>
<% end %>
</div>
</div>
表格显示了,但我现在遇到的唯一问题是在我提交后它没有创建任何 branch_history_solds
问题是您用来评估是否应拒绝嵌套记录的 lambda 将始终 return 为真,因为您的 form/model 没有 content
属性:
class Sale < ActiveRecord::Base
has_many :branch_history_solds
accepts_nested_attributes_for :branch_history_solds, :reject_if => lambda { |a| a[:content].blank? },
:allow_destroy => true
end
您还将错误的属性列入白名单 branch_history_sold
而不是 branch_history_solds
。
您需要将其更改为实际传递的属性:
class Sale < ActiveRecord::Base
has_many :branch_history_solds
accepts_nested_attributes_for :branch_history_solds, :reject_if => lambda { |a| a[:branch_product_id].blank? },
:allow_destroy => true
end
但是你的一般设置很奇怪,我不知道它是否只是命名但它没有多大意义。
如果您想创建一个销售点系统或订单管理系统,您可以这样做:
class Order
belongs_to :customer
has_many :line_items
has_many :products, through: :line_items
accepts_nested_attributes_for :line_items,
allow_destroy: true,
reject_if: -> { |li| li[:product_id].blank? || li[:quantity].blank? }
end
# columns:
# - order_id [integer, index, foreign key]
# - product_id [integer, index, foreign key]
# - quantity [decimal or integer]
# - price [decimal]
# - subtotal [decimal]
class LineItem
belongs_to :order
belongs_to :product
end
class Product
has_many :line_items
has_many :orders, through: :line_items
end
class OrdersController
def new
end
def create
@order = Order.new(order_params) do
order.customer = current_user
end
if (@order.save)
else
end
end
private
def order_params
params.require(:order)
.permit(:foo, :bar, line_item_attributes: [:product_id, :quantity])
end
end
请注意,您应该只让用户传递数量极其有限的参数 - 永远不要从用户那里获取价格之类的东西。实际的定价逻辑应该在模型层完成。您也不想从订单模型中分离客户详细信息 - 否则每个重复订单都会重复数据。在添加其他功能(如搜索)之前,我会花一些时间了解实际的领域模型。