Elise S
Elise S

Reputation: 75

Ruby / Rails - How to accept nested_attributes with has_many through relation on a form?

I'm building a web app in rails and I'm quite new with nested attributes. I'm trying to create a facture and I need to register Clients, Candidats and Deals params at the same time.

I found nested attributes as the best solution but it doesn't work identified as "unpermitted parameters" (that's the terminal says).

I build my Facture model with belongs_to relations with Clients, Candidates and Deals but I decided to create an intermediate table in order to create has_many through relation between Facture and others models.

But it doesn't correct the problem. I think I miss something maybe should I call the id but I don't really know how to do that.

Here is my model code :

class Facture < ApplicationRecord
    belongs_to :delais_paiement 
    belongs_to :service 
    belongs_to :marche 
    belongs_to :team 
    belongs_to :status_facturation 
    belongs_to :condition_facturation 
    has_many :candidats, through: :informations_factures
    has_many :clients, through: :informations_factures
    has_many :deals, through: :informations_factures
    has_many :informations_factures 

    accepts_nested_attributes_for :candidats
    accepts_nested_attributes_for :informations_factures
    accepts_nested_attributes_for :clients
    accepts_nested_attributes_for :deals
end

class Deal < ApplicationRecord
    belongs_to :client
    has_many :factures, through: :informations_factures
    has_many :informations_factures

    accepts_nested_attributes_for :factures
end
class Client < ApplicationRecord
    has_many :factures, through: :informations_factures
    has_many :informations_factures
end

class Candidat < ApplicationRecord
    has_many :factures, through: :informations_factures
    has_many :informations_factures
end

class InformationsFacture < ApplicationRecord
    belongs_to :candidat
    belongs_to :client
    belongs_to :deal
    belongs_to :facture
end

Here is my form :

        <%= simple_form_for @facture do |f| %>

          <div class="form-group">
            <%= f.input :salaire, label: "Salaire"%>
          </div>

          <div class="form-group">
            <%= f.input :condition_facturation_id, label: "Condition de facturation",  collection: ConditionFacturation::statuses.keys %>
          </div>

          <div class="form-group">
            <%= f.input :service_id, label: "Service", collection: Service::kinds.keys%>
          </div>

          <div class="form-group">
            <%= f.input :team_id, label: "Team", collection: @team%>
          </div>

          <div class="form-group">
            <h4>Candidat</h4>
            <%= f.simple_fields_for :candidat do |af| %> 
              <%= af.input :name, label: "Name" %>
              <%= af.input :id_janus, label: 'Id Janus' %>
            <% end %>
          </div>

          <div class="form-group">
            <h4>Client</h4>
            <%= f.simple_fields_for :client do |af| %>
              <%= af.input :name, label: "Name" %>
            <% end %>
          </div>

          <div class="form-group">
            <h4>Deal infos</h4>
            <%= f.simple_fields_for :deal do |af| %>
            <%= af.input :start_date, label: "Start Date" %>
            <%= af.input :deal_date, label: "Deal Date" %>
            <% end %>
          </div>

          <%= f.submit class: 'btn btn-primary' %>
        <% end %>

Here is my Facture Controller params code:

private 

def facture_params
 params.require(:facture).permit(
 :condition_facturation_id, :service_id, :team_id, 
 :salaire, {:client_id => [{:clients_attributes => [:name, :id]}]}, {:deals_attributes => [:deal_date, :start_date]}, {:candidats_attributes => [:name, :id_janus, :id]})
end

Here is my terminal action :

Started POST "/factures" for 127.0.0.1 at 2019-02-14 17:14:24 +0100
Processing by FacturesController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"mOmAyCZZwnG1RF7p9KSxMoNCgqxF6vVriC0YgjHAdS26pBIs73OKuhqkQurU0HVr8cotdRmUWjXFAeb+4ISjsA==", "facture"=>{"salaire"=>"1", "condition_facturation_id"=>"au_succes", "service_id"=>"recrutement",  "team_id"=>"2", "candidat"=>{"name"=>"Kévin", "id_janus"=>"#123456"}, "client"=>{"name"=>"Jean-luc"}, "deal"=>{"start_date"=>"12/28/19", "deal_date"=>"12/29/19"}}, "commit"=>"Create Facture"}
Unpermitted parameters: :candidat, :client, :deal

(0.2ms)  BEGIN
  ↳ app/controllers/factures_controller.rb:25
  Service Load (0.7ms)  SELECT  "services".* FROM "services" WHERE "services"."id" = $1 LIMIT $2  [["id", 0], ["LIMIT", 1]]
  ↳ app/controllers/factures_controller.rb:25
  Team Load (0.2ms)  SELECT  "teams".* FROM "teams" WHERE "teams"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
  ↳ app/controllers/factures_controller.rb:25
  ConditionFacturation Load (0.3ms)  SELECT  "condition_facturations".* FROM "condition_facturations" WHERE "condition_facturations"."id" = $1 LIMIT $2  [["id", 0], ["LIMIT", 1]]
  ↳ app/controllers/factures_controller.rb:25
   (0.1ms)  ROLLBACK
  ↳ app/controllers/factures_controller.rb:25
  Rendering factures/new.html.erb within layouts/application
  Rendered factures/new.html.erb within layouts/application (19.7ms)

What does I miss ?

Upvotes: 1

Views: 129

Answers (1)

Mark Weston
Mark Weston

Reputation: 1163

The "unpermitted parameters" error means this a problem in the Controller, specifically your "strong parameters" code.

I believe the problem is the way you have specified the permitted attributes for the nested objects.

Here's an untested version of what I think your facture_params method should look like. You might need to do some testing and fiddling to get it exactly right. In particular, whether the nested params need to include id fields depends on whether you want to accept params just to create new objects, or to update existing objects.

def facture_params
 params.require(:facture).permit(
   :condition_facturation_id, 
   :service_id, 
   :team_id, 
   :salaire,
   :clients_attributes => [:name, :id],
   :deals_attributes => [:deal_date, :start_date],
   :candidats_attributes => [:name, :id_janus, :id]
  )
end

Upvotes: 1

Related Questions