2017-01-31 4 views
0

sale.rb "Parent"Nested forme fields_for créer wont objets enfants rails 5

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 "Enfant"

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 

Et enfin ma forme avec l'attribut 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: "[email protected]", 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> 

La forme affiche mais le seul problème im ayant maintenant est qu'il ne crée aucun branch_history_sold après que je subm il

Répondre

2

Le problème est que le lambda que vous utilisez pour évaluer si les dossiers imbriqués doivent être rejetés retournera toujours vrai que votre formulaire/modèle ne possède pas d'attribut 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 

Vous êtes aussi liste blanche des mauvais attributs branch_history_sold pas branch_history_solds.

Vous devez changer pour être un attribut qui est réellement passé:

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 

Cependant votre configuration générale est tout simplement étrange et je ne sais pas si son juste la dénomination mais il ne fait pas grand-chose sens.

Si vous voulez créer un système de point de vente ou d'un système de gestion des commandes que vous le feriez comme ceci:

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 

Notez que vous ne devez permettre aux utilisateurs de passer un nombre extrêmement limité de params - ne jamais prendre des choses comme les prix de l'utilisateur. La logique de tarification réelle doit être effectuée sur la couche du modèle. Vous ne voulez pas non plus détacher les détails du client du modèle de commande - sinon chaque commande répétée dupliquera les données. Je passerais du temps à obtenir le modèle de domaine réel avant d'ajouter des fonctionnalités supplémentaires comme la recherche.

+1

Si vous voulez garder une trace de l'inventaire, vous devriez le faire avec des modèles supplémentaires - n'essayez pas de le faire dans ce qui précède. Vous aurez besoin d'un modèle qui garde la trace des emplacements (magasins, succursales, etc) et un modèle qui garde la trace de l'inventaire d'un produit à un emplacement. – max

+0

@oklas le relire. Ajout d'une coquille dans la liste blanche du contrôleur - pas dans le modèle. Votre commentaire n'a même pas de sens. – max