mardi 4 juillet 2023

Difficulties to create in database with cocookn / nested form

Good morning

I've been trying to save the content of a nested form in a database for a while now. I have a main form dependent on the Supplier model, and I have another SupplierRestaurantDelivery model which is there to define A delivery_day = day on which the restaurant can be delivered An order_day = day for which you must order to be delivered on delivery_day (display via javascript if delivery_day is checked) A max_hour_order = valid for all delivery_day

The purpose of the SupplierRestaurantDelivery model is to be able to calculate the possible delivery days for a restaurant.

Here are my three models:

class Supplier < ApplicationRecord
  has_many :ingredients
  has_many :supplier_orders
  has_many :supplier_restaurant_deliveries, inverse_of: :supplier
  accepts_nested_attributes_for :supplier_restaurant_deliveries, reject_if: :all_blank, allow_destroy: true

  validates :name, uniqueness: { case_sensitive: false }
  validates :franco, presence: true, numericality: { greater_than: 0 }
end

class SupplierRestaurantDelivery < ApplicationRecord
  belongs_to :restaurant, inverse_of: :supplier_restaurant_deliveries
  belongs_to :supplier, polymorphic: true
end

class Restaurant < ApplicationRecord
  belongs_to :company
  has_many :supplier_orders, dependent: :destroy
  has_many :user_restaurants
  has_many :users, through: :user_restaurants
  has_many :supplier_restaurant_deliveries
end

Here is my controller:

class SuppliersController < ApplicationController
  def index
    @suppliers = policy_scope(Supplier)
  end

  def new
    @supplier = Supplier.new
    @supplier.supplier_restaurant_deliveries.build
    authorize @supplier
  end

  def create
    @supplier = Supplier.new(supplier_params)
    puts "=======>>>>>  Create supplier"
    # @restaurant_id = current_user.current_restaurant_id
    puts "=======>>>>>  ID restaurant #{@restaurant_id}"
    @supplier.restaurant_id = current_user.current_restaurant_id
    # @supplier.update(restaurant_id: @restaurant_id)
    puts "=======>>>>>  errors :  #{@supplier.errors.full_messages}"
    puts "=======>>>>>  Restaurant added to :  #{@supplier}"

    if @supplier.save
      puts @supplier.errors.full_messages
      puts "=======>>>>>  I just pass @supplier.save "
      create_delivery_entries
      puts "=======>>>>> I just pass create_delivery_entries "

      redirect_to suppliers_path, notice: "Supplier was successfully created."
    else
      puts @supplier.errors.full_messages
      render :new, status: :unprocessable_entity
    end
    authorize @supplier
  end

  def create_delivery_entries
    delivery_days = params[:supplier][:supplier_restaurant_deliveries_attributes]["0"][:delivery_day] # Les jours de livraison sélectionnés
    order_days = params[:supplier][:supplier_restaurant_deliveries] # Les jours de commande pour chaque entrée
    puts "=======>>>>>  Delivery Days: #{delivery_days.inspect}"
    puts "=======>>>>>  Order Days: #{order_days.inspect}"

    delivery_days.each_with_index do |selected, index|
      day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][index]
      puts "Day: #{day}, Selected: #{selected}"
      puts "=======>>>>>  index: #{index} // day: #{selected}"
      next unless order_days[index].present? # Ignorer l'itération si order_days[index] est nil

      order_day = order_days[index][:order_day]
      puts "=======>>>>>  order day: #{order_day}"
      @supplier.supplier_restaurant_deliveries.create(delivery_day: day, order_day: order_day, supplier_type: 'Supplier')
      puts "=======>>>>>  created ... "
    end
  end


  def edit
    @supplier = Supplier.find(params[:id])
    authorize @supplier
  end

  def update
    @supplier = Supplier.find(params[:id])
    @supplier.update(supplier_params)
    if @supplier.save
      redirect_to suppliers_path
    else
      render :edit, status: :unprocessable_entity
    end
    authorize @supplier
  end

  def destroy
    @supplier = Supplier.find(params[:id])
    if @supplier.destroy
      flash[:notice] = "Le supplier a été supprimé avec succès."
    else
      flash[:error] = "Une erreur s'est produite lors de la suppression du supplier."
    end
    authorize @supplier
  end

  private

  def supplier_params
    params.require(:supplier).permit(
      :name,
      :address,
      :zip_code,
      :city, :phone,
      :franco,
      supplier_restaurant_delivery_attributes: [
        :id,
        :order_day,
        :max_hour_order,
        :_destroy,
        delivery_day: []
      ]
    )
  end
end

Forms :



<div class="container">
  <%= simple_form_for(supplier) do |f| %>
  <%= f.input :name, input_html: { class: "form-control" } %>
  <%= f.input :address, input_html: { class: "form-control" } %>
  <%= f.input :zip_code, input_html: { class: "form-control" } %>
  <%= f.input :city, input_html: { class: "form-control" } %>
  <%= f.input :phone, input_html: { class: "form-control" } %>
  <%= f.input :franco, input_html: { class: "form-control" } %>

  <div id="supplier_restaurant_deliveries">
    <%= f.fields_for :supplier_restaurant_deliveries do |delivery_fields| %>
      <%= render 'supplier_restaurant_delivery_fields', f: delivery_fields %>
    <% end %>
  </div>


    <%= f.button :submit, class: 'btn btn-primary' %>
<% end %>
</div>


Nested form :

  <div class="nested-fields">
    <%= f.input :max_hour_order, as: :string, input_html: { class: 'timepicker', placeholder: 'HH:MM', value: '' } %>
    <table class=" table table-striped table-hover" data-controller="supplier-delivery-options" >
      <thead>
        <tr>
          <th scope="col">Delivered?</th>
          <th scope="col">Order day</th>
        </tr>
      </thead>
        <tbody>
      <% ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'].each do |day| %>
          <tr>
            <td>
              <div class="form-check form-switch">
                <% checkbox_id = "flexSwitchCheckDefault_#{day.downcase}" %>
                <%= f.check_box :delivery_day,
                              class: 'form-check-input', type: 'checkbox', role: 'switch', id: checkbox_id,
                              data: {
                                action: "change->supplier-delivery-options#select",
                                check: day.downcase
                              },
                              multiple: true,
                              label: false %>
                <label class="form-check-label" for="<%= checkbox_id %>"><%= day %></label>
              </div>
            </td>
            <td>
              <%= f.input :order_day,
                                    label: false,
                                    collection: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
                                    input_html: { disabled: true, data: { list: "#{day}" }, name: "supplier[supplier_restaurant_deliveries][][order_day]" } %>
            </td>
          </tr>
        </tbody>
      <% end %>
    </table>

</div>

I see it's stuck in the settings. If I put supplier_restaurant_deliveries_attributes, it blocks at @supplier.save If I put supplier_restaurant_delivery_attributes, then it goes much further. We can observe in the console what is blocking. Another element that challenges me in this console: why do I have an array of 8 elements returned for the 7 days when I only announce the 7 days of the week?

I selected my example in delivery day: wednesday and order_day: Tuesday, as well as delivery_day: saturday and order_day: friday

Console view :

Started POST "/suppliers" for 127.0.0.1 at 2023-07-04 10:08:50 +0200
Processing by SuppliersController#create as TURBO_STREAM
  Parameters: {"authenticity_token"=>"[FILTERED]", "supplier"=>{"name"=>"test 30", "address"=>"", "zip_code"=>"", "city"=>"", "phone"=>"", "franco"=>"150", "supplier_restaurant_deliveries_attributes"=>{"0"=>{"max_hour_order"=>"15", "delivery_day"=>["0", "0", "0", "1", "0", "0", "0", "1", "0"]}}, "supplier_restaurant_deliveries"=>[{"order_day"=>"Tuesday"}, {"order_day"=>"Friday"}]}, "commit"=>"Create Supplier"}
  User Load (0.9ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
Unpermitted parameters: :supplier_restaurant_deliveries_attributes, :supplier_restaurant_deliveries. Context: { controller: SuppliersController, action: create, request: #<ActionDispatch::Request:0x00007fbd78012100>, params: {"authenticity_token"=>"[FILTERED]", "supplier"=>{"name"=>"test 30", "address"=>"", "zip_code"=>"", "city"=>"", "phone"=>"", "franco"=>"150", "supplier_restaurant_deliveries_attributes"=>{"0"=>{"max_hour_order"=>"15", "delivery_day"=>["0", "0", "0", "1", "0", "0", "0", "1", "0"]}}, "supplier_restaurant_deliveries"=>[{"order_day"=>"Tuesday"}, {"order_day"=>"Friday"}]}, "commit"=>"Create Supplier", "controller"=>"suppliers", "action"=>"create"} }
=======>>>>>  Create supplier
=======>>>>>  ID restaurant
=======>>>>>  errors :  []
=======>>>>>  Restaurant added to :  #<Supplier:0x00007fbd233e8e78>
  TRANSACTION (0.9ms)  BEGIN
  ↳ app/controllers/suppliers_controller.rb:22:in `create'
  Supplier Exists? (9.2ms)  SELECT 1 AS one FROM "suppliers" WHERE LOWER("suppliers"."name") = LOWER($1) LIMIT $2  [["name", "test 30"], ["LIMIT", 1]]
  ↳ app/controllers/suppliers_controller.rb:22:in `create'
  Supplier Create (9.8ms)  INSERT INTO "suppliers" ("name", "address", "zip_code", "city", "phone", "franco", "created_at", "updated_at", "restaurant_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"  [["name", "test 30"], ["address", ""], ["zip_code", nil], ["city", ""], ["phone", ""], ["franco", "150"], ["created_at", "2023-07-04 08:08:50.636762"], ["updated_at", "2023-07-04 08:08:50.636762"], ["restaurant_id", 2]]
  ↳ app/controllers/suppliers_controller.rb:22:in `create'
  TRANSACTION (3.7ms)  COMMIT
  ↳ app/controllers/suppliers_controller.rb:22:in `create'
=======>>>>>  I just pass @supplier.save
=======>>>>>  Delivery Days: ["0", "0", "0", "1", "0", "0", "0", "1", "0"]
=======>>>>>  Order Days: [#<ActionController::Parameters {"order_day"=>"Tuesday"} permitted: false>, #<ActionController::Parameters {"order_day"=>"Friday"} permitted: false>]
Day: Monday, Selected: 0
=======>>>>>  index: 0 // day: 0
=======>>>>>  order day: Tuesday
=======>>>>>  created ...
Day: Tuesday, Selected: 0
=======>>>>>  index: 1 // day: 0
=======>>>>>  order day: Friday
=======>>>>>  created ...
Day: Wednesday, Selected: 0
=======>>>>>  index: 2 // day: 0
Day: Thursday, Selected: 1
=======>>>>>  index: 3 // day: 1
Day: Friday, Selected: 0
=======>>>>>  index: 4 // day: 0
Day: Saturday, Selected: 0
=======>>>>>  index: 5 // day: 0
Day: Sunday, Selected: 0
=======>>>>>  index: 6 // day: 0
Day: , Selected: 1
=======>>>>>  index: 7 // day: 1
Day: , Selected: 0
=======>>>>>  index: 8 // day: 0
=======>>>>> I just pass create_delivery_entries
Redirected to http://localhost:3000/suppliers
Completed 302 Found in 64ms (ActiveRecord: 31.5ms | Allocations: 9494)


Started GET "/suppliers" for 127.0.0.1 at 2023-07-04 10:08:50 +0200
Processing by SuppliersController#index as TURBO_STREAM
  User Load (0.6ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Rendering layout /home/quentinvandenbulcke/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/turbo-rails-1.4.0/app/views/layouts/turbo_rails/frame.html.erb
  Rendering suppliers/index.html.erb within layouts/turbo_rails/frame
  Supplier Load (0.9ms)  SELECT "suppliers".* FROM "suppliers"
  ↳ app/views/suppliers/index.html.erb:25
  Rendered suppliers/index.html.erb within layouts/turbo_rails/frame (Duration: 9.7ms | Allocations: 2408)
  Rendered layout /home/quentinvandenbulcke/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/turbo-rails-1.4.0/app/views/layouts/turbo_rails/frame.html.erb (Duration: 11.5ms | Allocations: 2633)
Completed 200 OK in 20ms (Views: 12.7ms | ActiveRecord: 1.5ms | Allocations: 4701)

Thanks a lot for your help

Aucun commentaire:

Enregistrer un commentaire