Как использовать вложенные формы с различными отношениями, используя самоцвет кокона? - PullRequest
1 голос
/ 06 мая 2019

Моя дилемма существует уже неделю, я пытаюсь ее решить, но пока не могу, поэтому я прошу помощи.

У меня есть модель дилерского центра и другие вложенные(DealershipsSetting, Address, Machines, Operators, Cards), где отношение has_one применяется только к DealershipsSetting, поэтому остальные имеют has_many.Я могу только записать некоторую информацию в таблицы базы данных, когда я вызываю метод построения для каждой модели вложенных форм, например:

  def new
    @dealership = Dealership.new
    @ dealership.build_dealerships_setting if @ dealership.dealerships_setting.blank?
    @ dealership.addresses.build if @ dealership.addresses.blank?
...
  end

  def edit
    @ dealership.build_dealerships_setting if @ dealership.dealerships_setting.blank?
    @ dealership.addresses.build if @ dealership.addresses.blank?
...
  end

Я понимаю:

a) ПервыйВ журнале я замечаю, что формы перенаправляются несколько раз.Это имеет смысл, так как я заставляю их строить через вызов builds (по крайней мере, я так понимаю).Но это не стандартное поведение при использовании драгоценного камня, я протестировал в другом приложении, чтобы узнать, как использовать драгоценный камень, следуя документации https://github.com/nathanvda/cocoon

б) Из-за вызова метода сборки,формы открываются (готовы к приему данных), я не знаю, является ли это поведением по умолчанию.

c) Когда я вызываю Action New или Edit, я не могу записать более одной записи (тип, 2адреса, 3 карты или N операторов)

d) В документации я не заметил никакого вызова метода сборки, я нашел в поисках, чтобы попытаться решить мою проблему, например, https://share.atelie.software/rails-nested-attributes-com-has-many-42ecf6179871

e) Если я удаляю вызовы из сборок, следуя примерам, доступным в документации, поля будут скрыты до тех пор, пока вы не вызовете через link_to_add_association, но никакие данные из вложенных форм не сохранятся.

Когда я настраиваю свой дилерский центр вот так, я не могу добавить регистр в базу данных:

def new    
   @dealership = Dealership.new        
end
...
def create
   @dealership = Dealership.new(dealership_params)

   respond_to do |format|
     if @dealership.save
        format.html { redirect_to users_backend_dealerships_path, notice: 'Dealership was successfully created.' }
        format.json { render :show, status: :created, location: @dealership }
     else
        format.html { render :new }
        format.json { render json: @dealership.errors, status: :unprocessable_entity }
     end
   end
 end
....

def dealership_params
  params.require(:dealership).permit(
:fantasy_name, :social_name, :cpf, :cnpj, :municipal_registration, :state_registration, :credit, :phone, :manager_email, :is_available, :credits_package_id, dealerships_setting_attributes: [:id, :credit_alert, :contract_validity, :franchise_for_rent, :due_date, :credit_value, :is_available, :_destroy],addresses_attributes: [:id, :place, :neighborhood, :cep, :state, :city, :is_available, :_destroy], machines_attributes: [:id, :name, :model, :serial_number, :mac_address, :calibration_counter, :is_available, :_destroy], operators_attributes: [:id, :name, :cpf, :card, :is_available, :_destroy ], cards_attributes: [:id, :serial, :category, :credit_package, :client, :machine, :operator, :is_available, :_destroy ])
end

Таким образом, я могу добавить один регистр по модели в базе данных..

дилерский центр_контроллер

class UsersBackend :: DealershipsController <UsersBackendController
  before_action: set_dealership, only: [: show,: edit,: update,: destroy]
  before_action: get_credit_packages, only: [: edit,: update,: new]
 
 def index
    @dealerships = Dealership.includes(:dealerships_setting, :addresses, :machines, :operators, :cards)
  end

  def show
  end

  def add_credits
  end

  def new
    @dealership = Dealership.new        
    @dealership.build_dealerships_setting if @dealership.dealerships_setting.blank?
    @dealership.addresses.build if @dealership.addresses.blank?
    @dealership.machines.build if @dealership.machines.blank?
    @dealership.operators.build if @dealership.operators.blank?
    @dealership.cards.build if @dealership.cards.blank?
  end

  def edit
    @dealership.build_dealerships_setting if @dealership.dealerships_setting.blank?
    @dealership.addresses.build if @dealership.addresses.blank?
    @dealership.machines.build if @dealership.machines.blank?
    @dealership.operators.build if @dealership.operators.blank?
    @dealership.cards.build if @dealership.cards.blank?
  end

  def create
    @dealership = Dealership.new(dealership_params)

    respond_to do |format|
      if @dealership.save
        format.html { redirect_to users_backend_dealerships_path, notice: 'Dealership was successfully created.' }
        format.json { render :show, status: :created, location: @dealership }
      else
        format.html { render :new }
        format.json { render json: @dealership.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if @dealership.update(dealership_params)
        format.html { redirect_to users_backend_dealerships_path, notice: 'Dealership was successfully updated.' }
        format.json { render :show, status: :ok, location: @dealership }
      else
        format.html { render :edit }
        format.json { render json: @dealership.errors, status: :unprocessable_entity }
      end
    end
  end

def destroy
    @dealership.destroy
    respond_to do |format|
      format.html { redirect_to users_backend_dealerships_path, notice: 'Dealership was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private

    def set_dealership
      @dealership = Dealership.find(params[:id])
    end

    def dealership_params
      params.require(:dealership).permit(:fantasy_name, :social_name, :cpf, :cnpj, :municipal_registration, :state_registration, :credit, :phone, :manager_email, :is_available, :credits_package_id,
        dealerships_setting_attributes: [:id, :credit_alert, :contract_validity, :franchise_for_rent, :due_date, :credit_value, :is_available, :_destroy],
        addresses_attributes: [:id, :place, :neighborhood, :cep, :state, :city, :is_available, :_destroy],
        machines_attributes: [:id, :name, :model, :serial_number, :mac_address, :calibration_counter, :is_available, :_destroy], 
        operators_attributes: [:id, :name, :cpf, :card, :is_available, :_destroy ],
        cards_attributes: [:id, :serial, :category, :credit_package, :client, :machine, :operator, :is_available, :_destroy ]
        )
    end

    def get_credit_packages
      @credit_packages = CreditsPackage.where(media_owner: 0)
    end
end

модель дилерского центра.рб

class Dealership < ApplicationRecord

  has_many :credits_packages

  has_one :dealerships_setting, dependent: :destroy, inverse_of: :dealership

  has_many :addresses, dependent: :destroy, inverse_of: :dealership
  has_many :machines, dependent: :destroy, inverse_of: :dealership
  has_many :operators, dependent: :destroy, inverse_of: :dealership
  has_many :cards, dependent: :destroy, inverse_of: :dealership


  accepts_nested_attributes_for :dealerships_setting, reject_if: :all_blank, allow_destroy: true

  accepts_nested_attributes_for :addresses, reject_if: :all_blank, allow_destroy: true
  accepts_nested_attributes_for :machines, reject_if: :all_blank, allow_destroy: true
  accepts_nested_attributes_for :operators, reject_if: :all_blank, allow_destroy: true
  accepts_nested_attributes_for :cards, reject_if: :all_blank, allow_destroy: true

  accepts_nested_attributes_for :users, reject_if: :all_blank, allow_destroy: true
end

модель дилерского центра_наладка

class DealershipsSetting < ApplicationRecord
  belongs_to :dealership, inverse_of: :dealerships_setting
end

модель адреса.рб

class Address < ApplicationRecord
  belongs_to :dealership
end

form.html.erb (представительство)

<%= form_with(model: [ :users_backend, @dealership], local: true) do |form| %>
     <div class="form-group">
          <strong><%= form.label :fantasy_name %></strong>
               <%= form.text_field :fantasy_name, autofocus: true, class:"text-uppercase form-control", placeholder:t('place_holders.fantasy_name') %>
     </div>
...

<%= form.fields_for :dealerships_setting, @dealership.dealerships_setting do |dealerships_setting| %>
     <%= render partial: 'dealerships_setting_fields', locals: { f: dealerships_setting } %>
  <% end %>

<div id="addresses"> 
    <%= form.fields_for :addresses do |address| %> 
<%= render partial: 'address_fields', locals: { f: address } %>
    <% end %>
    <%= link_to_add_association('Add address', form, :addresses) %>
 </div> 
....others nested forms...

_dealerships_setting_fields.html.erb

<div class="nested-fields">
  <div class="form-group">
    <strong><%= f.label :contract_validity %></strong>
    <%= f.text_field :contract_validity, class:"form-control ", placeholder:t('place_holders.contract_validity') %>
  </div> ...another fields...

_address_fields.html.erb

<div class='nested-fields'>
  <div class='form-group'>
    <strong><%= f.label :place %></strong>
    <%= f.text_field :place, class:"text-uppercase form-control", placeholder:t('place_holders.place') %>
  </div> ...another fields...

Чтонужно ли мне?О - Управляйте дилерскими центрами, где у них должна быть одна конфигурация и один или несколько адресов, машин, операторов и карт.

Я буду очень благодарен всем, кто может мне помочь.

1 Ответ

0 голосов
/ 11 мая 2019

Хорошо, поэтому я столкнулся с двумя основными ошибками:

  • ваш тег формы находился внутри элемента div, но содержимое формы охватывало несколько элементов div.Он будет выглядеть правильно, но не будет публиковать правильную информацию во всех случаях
  • во-вторых: у вас были проверки, блокирующие сохранение, в моем случае, и затем произошли две вещи:
    • вы не установили@credit_packages в вашем create действии, выдававшем ошибку при повторной визуализации формы
    • , вы не показали никакой ошибки валидации (поэтому нет обратной связи относительно того, почему не удалось сохранить)

Итак, я сделал две вещи.В вашем dealerships_controller я отредактировал следующую строку

before_action :get_credit_packages, only: [:edit, :update, :new, :create] 

(также установите кредитные пакеты при создании)

А на вашем _form.html.erb я переместил form_with прямо под rowdiv, и добавил немного элементарного отображения ошибок валидации.row div никогда не закрывался.Ваша полная форма:

<!-- Page Heading -->
<h1 class="h3 mb-4 text-gray-800"><%= action_message %></h1>
<div class="row">
  <%= form_with(model: [ :users_backend, @dealership], local: true) do |form| %>

    <p>
      <%= @dealership.errors.messages.inspect %>
    </p>


    <div class="col-lg-6"> <!-- card Dealerships Information-->
      <div class="card border-left-danger shadow mb-4">
        <a href="#collapseCardDealershipInformation" class="d-block card-header py-3" data-toggle="collapse" role="button" aria-expanded="true" aria-controls="collapseCardDealershipInformation"><h6 class="m-0 font-weight-bold text-primary"><%= t('labels.dealership_information') %></h6></a>
        <div class="collapse show" id="collapseCardDealershipInformation"> <!-- card Content - Collapse -->
          <div class="card-body">
            <div class="form-group">
              <strong><%= form.label :fantasy_name %></strong>
              <%= form.text_field :fantasy_name, autofocus: true, class:"text-uppercase form-control", placeholder:t('place_holders.fantasy_name') %>
            </div>

            <div class="form-group">
              <strong><%= form.label :social_name %></strong>
              <%= form.text_field :social_name, class:"text-uppercase form-control", placeholder:t('place_holders.social_name') %>
            </div>

            <div class="form-group row">
              <div class="col-md-6">
                <strong><%= form.label :phone %></strong>
                <%= form.text_field :phone, class:"form-control", placeholder:t('place_holders.phone') %>
              </div>
              <div class="col-md-6">
                <strong><%= form.label :manager_email %></strong>
                <%= form.text_field :manager_email, class:"text-downcase form-control", placeholder:t('place_holders.manager_email') %>
              </div>
            </div>

            <div class="form-group row">
              <div class="col-md-6">
                <strong><%= form.label :cpf %></strong>
                <%= form.text_field :cpf, class:"form-control", placeholder:t('place_holders.cpf') %>
              </div>
              <div class="col-md-6">
                <strong><%= form.label :cnpj %></strong>
                <%= form.text_field :cnpj, class:"form-control", placeholder:t('place_holders.cnpj') %>
              </div>
            </div>

            <div class="form-group row">
              <div class="col-md-6">
                <strong><%= form.label :municipal_registration %></strong>
                <%= form.text_field :municipal_registration, class:"form-control form-control-user", placeholder:t('place_holders.municipal_registration') %>
              </div>
              <div class="col-md-6">
                <strong><%= form.label :state_registration %></strong>
                <%= form.text_field :state_registration, class:"form-control form-control-user", placeholder:t('place_holders.state_registration') %>
              </div>
            </div>

            <div class="form-group">
              <strong><%= form.label :credits_package %></strong>
              <%= form.collection_select(:credits_package_id, @credit_packages, :id, :name, {:prompt => t('prompt.credits_package')}, { class:"form-control" }) %>
            </div>

            <div class="form-group custom-control custom-checkbox small ">
              <%= form.check_box :is_available, class:"custom-control-input" %>
              <%= form.label :is_available, class:"custom-control-label" %>
            </div>

          </div> <!-- .card-body-->
        </div><!-- . card Content - Collapse -->
      </div> <!-- .mb4-->
    </div> <!-- .Dealerships Information (lg-6) -->

    <div class="col-lg-6"> <!-- card Financial Settings -->
      <div class="card border-left-danger shadow mb-4">
        <a href="#collapseCardDealershipFinancialSettings" class="d-block card-header py-3" data-toggle="collapse" role="button" aria-expanded="true" aria-controls="collapseCardDealershipFinancialSettings"><h6 class="m-0 font-weight-bold text-primary"><%= t('labels.financial_settings') %></h6></a>
          <div class="collapse show" id="collapseCardDealershipFinancialSettings">
            <div class="card-body">
              <%= form.fields_for :dealerships_setting, @dealership.dealerships_setting do |dealerships_setting| %>
                <%= render partial: 'dealerships_setting_fields', locals: { f: dealerships_setting } %>
              <% end %>
            </div> <!--card-body -->
          </div> <!--collapse card dealership Financial settings -->
      </div><!--mb-4 -->
    </div> <!-- .Financial Settings (lg-6) -->

    <div class="col-lg-12"> <!-- card Addresses -->
      <div class="card border-left-danger shadow mb-4">
        <a href="#collapseCardAddressess" class="d-block card-header py-3" data-toggle="collapse" role="button" aria-expanded="true" aria-controls="collapseCardAddressess"><h6 class="m-0 font-weight-bold text-primary"><%= t('labels.addresses') %></h6></a>
          <div class="collapse show" id="collapseCardAddressess">
            <div class="card-body">
              <div id="addresses">
                <%= form.fields_for :addresses do |address| %>
                  <%= render partial: 'address_fields', locals: { f: address } %>
                <% end %>
                <%= link_to_add_association('Adicionar endereço', form, :addresses) %>
              </div> <!--  addresses -->
            </div> <!--card-body -->
          </div> <!--collapse card dealership Addressess -->
      </div> <!-- mb-4 -->
    </div>  <!--col-lg-12 -->

    <div class="col-lg-12"> <!-- card Machines-->
      <div class="card border-left-warning shadow mb-4">
        <a href="#collapseCardDealershipMachines" class="d-block card-header py-3" data-toggle="collapse" role="button" aria-expanded="true" aria-controls="collapseCardDealershipMachines"><h6 class="m-0 font-weight-bold text-primary"><%= t('labels.machines') %></h6></a>
          <div class="collapse show" id="collapseCardDealershipMachines">
            <div class="card-body">
              <div id="machines">
                <%= form.fields_for :machines do |machine| %>
                  <%= render partial: 'machine_fields', locals: { f: machine } %>
                <% end %>
                <%= link_to_add_association('Adicionar equipamento', form, :machines) %>
              </div> <!-- machines -->
            </div> <!--card-body -->
          </div> <!--collapse card machines -->
      </div><!--mb-4 -->
    </div>  <!--col-lg-12 -->

    <div class="col-lg-6"> <!-- card Operators-->
      <div class="card border-left-warning shadow mb-4">
        <a href="#collapseCardDealershipOperators" class="d-block card-header py-3" data-toggle="collapse" role="button" aria-expanded="true" aria-controls="collapseCardDealershipOperators"><h6 class="m-0 font-weight-bold text-primary"><%= t('labels.operators') %></h6></a>
          <div class="collapse show" id="collapseCardDealershipOperators">
            <div class="card-body">
              <div id="operators">
                <%= form.fields_for :operators do |operator| %>
                  <%= render partial: 'operator_fields', locals: { f: operator } %>
                <% end %>
                <%= link_to_add_association('Adicionar operador', form, :operators) %>
              </div> <!-- operators -->
            </div> <!--card-body -->
          </div> <!--collapse card dealership settings information -->
      </div><!--mb-4 -->
    </div>  <!--.Operators (lg-6) -->

    <div class="col-lg-6"> <!-- Card Cards =) -->
      <div class="card border-left-warning shadow mb-4">
        <a href="#collapseCardDealershipCards" class="d-block card-header py-3" data-toggle="collapse" role="button" aria-expanded="true" aria-controls="collapseCardDealershipCards"><h6 class="m-0 font-weight-bold text-primary"><%= t('labels.cards') %></h6></a>
        <div class="collapse show" id="collapseCardDealershipCards">
          <div class="card-body">
            <div id="cards">
              <%= form.fields_for :cards do |c| %>
                <%= render partial: 'card_fields', locals: { f: c } %>
              <% end %>
              <%= link_to_add_association('Adicionar cartão', form, :cards) %>
            </div> <!-- cards -->
          </div> <!--card-body -->
        </div> <!--collapse card dealership cards -->
      </div><!--mb-4 -->
    </div>  <!--.Cards -->

    <div class="actions">
      <div class="col-sm-4 mb-3 mb-sm-0 ">
        <%= form.submit t('buttons.save'), class:"btn btn-success btn-user"%>
      </div>
    </div> <!-- actions -->

  <% end %>
</div>

И тогда я смог сохранить автосалон.Я почему-то не разбираюсь в макете, но я позволю вам это исправить (класс css не ведет себя так, как я ожидаю?).

Примечание: это одна из причин, по которой я предпочитаю (или советую) использовать такие библиотеки, как haml, slim, .. потому что ваш код просмотра будет легче читать / поддерживать и он будет корректным.

...