Search code examples
ruby-on-railsrubynested-attributesruby-on-rails-7

Unpermitted Params using Polymorphic Association in Rails 7


enter image description here

Based on image above, I do a simple example.

Model: Person

class Person < ApplicationRecord
  belongs_to :personable, polymorphic: true
end

Model: Customer

class Customer < ApplicationRecord
  has_one :person, as: :personable
  accepts_nested_attributes_for :person
end

Controller: customers_controller

def new
  @customer = Customer.new
  @customer.build_person
end

def create
  @customer = Customer.new(customer_params)
  @customer.save
  redirect_to customers_path
end

private

def customer_params
  params.require(:customer).permit(:id, person_attributes: [:id, :name, :personable_type, :personable_id])
end

View

<%= form_with(model: customer) do |form| %>
  <%= form.fields_for customer.person do |form_fields| %>
    <%= form_fields.label :name %>
    <%= form_fields.text_field :name %>
  <% end %>
  <div>
    <%= form.submit %>
  </div>
<% end %>

When I run using Rails Console it's okay, according code below.

c = Customer.create()
Person.create(name: "Saulo", personable: c)

But when I run using view and controller, i receive the error below.

Unpermitted parameter: :person. Context: { controller: CustomersController, action: create, request: #<ActionDispatch::Request:0x00007fdad45e3650>, params: {"authenticity_token"=>"[FILTERED]", "customer"=>{"person"=>{"name"=>"Alisson"}}, "commit"=>"Create Customer", "controller"=>"customers", "action"=>"create"} }

I believe that the error its in method customer_params, but i don't found a way to resolve it.


Solution

  • Rails is expecting the person attributes to be nested under person_attributes, but the form is sending them under person instead.

    To fix this, ensure that fields_for is correctly setting up the fields to be nested under person_attributes in the form:

    <%= form_with(model: [customer, customer.build_person]) do |form| %>
      <%= form.fields_for :person_attributes, customer.person do |person_form| %>
        <%= person_form.label :name %>
        <%= person_form.text_field :name %>
      <% end %>
      <%= form.submit %>
    <% end %>
    

    This should generate the correct parameter name (person_attributes) for the nested attributes.