SamuraiBlue
SamuraiBlue

Reputation: 861

Rails4: Unpermitted parameter with using nested attributes

Unpermitted parameter is displayed when I try to create new data. Althogh there are many similar questions, I can't find out how to solve.

What I'd like to do is to save the value in the amounts table when create schedule.

log

Processing by SchedulesController#create as HTML
  Parameters: {"utf8"=>"?", "authenticity_token"=>"xxx", "schedule"=>{"title"=>"test title", "departure_date"=>"2016-07-06", "rooms_attributes"=>{"0"=>{"schedule_id"=>"", "amounts_attributes"=>{"0"=>{"schedule_id"=>"", "room_id"=>""}}}}}, "commit"=>"Create my schedule"}
  Parameters: {"utf8"=>"?", "authenticity_token"=>"xxx", "schedule"=>{"title"=>"test title", "departure_date"=>"2016-07-06", "rooms_attributes"=>{"0"=>{"schedule_id"=>"", "amounts_attributes"=>{"0"=>{"schedule_id"=>"", "room_id"=>""}}}}}, "commit"=>"Create my schedule"}
  User Load (120.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1  [["id", 1]]
  User Load (120.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1  [["id", 1]]
Unpermitted parameter: amounts_attributes

models

schedule.rb

class Schedule < ActiveRecord::Base
  belongs_to :user
  has_many :rooms, inverse_of: :schedule, dependent: :destroy
  has_many :amounts, inverse_of: :schedule, dependent: :destroy
  accepts_nested_attributes_for :rooms, allow_destroy: true
  accepts_nested_attributes_for :amounts, allow_destroy: true

rooms.rb

class Room < ActiveRecord::Base
  belongs_to :schedule, inverse_of: :rooms
  has_many :events, inverse_of: :room, dependent: :destroy
  has_many :amounts, inverse_of: :room, dependent: :destroy
  accepts_nested_attributes_for :events, allow_destroy: true
  accepts_nested_attributes_for :amounts, allow_destroy: true

amount.rb

class Amount < ActiveRecord::Base
  belongs_to :schedule, inverse_of: :amounts
  belongs_to :room, inverse_of: :amounts
  belongs_to :event, inverse_of: :amounts
end

controller

schedule_controller.rb

  def new
    @schedule = Schedule.new
    room = @schedule.rooms.build
    room.amounts.build
  end

  def create
    @schedule = current_user.schedules.build(schedule_params)
    if @schedule.save
      flash[:success] = "schedule created!"
      redirect_to schedule_path(@schedule)
    else
      render 'new'
    end
  end

...

  def schedule_params
    params.require(:schedule).permit(
      :title, :departure_date, 
      rooms_attributes: [
        :id, :_destroy, :room, :room_address, :schedule_id, :day,  
        amounts_attributes: [
          :schedule_id, :room_id, :event_id, :id, :_destroy, :ccy, :amount
        ]
      ]
    )
  end

view

/schedules/new.html.erb

...
<%= form_for(@schedule) do |f| %>
  <%= render 'schedule_form', f: f %>
  <%= f.submit "Create my schedule", class: "btn btn-primary" %>
...

/schedules/ _schedule_form.html.erb

It works before adding 4 lines for <%= room.fields_for(:amounts) do |amount| %>.

...
  <%= f.label :title %>
  <%= f.text_field :title, class: 'form-control' %>
...

<%= f.fields_for(:rooms) do |room| %>
  <%= room.hidden_field :schedule_id %>

  <%= room.fields_for(:amounts) do |amount| %> # my app works before add these 4 lines.
    <%= amount.hidden_field :schedule_id %>    #
    <%= amount.hidden_field :room_id %>        #
  <% end %>                                    #

<% end %>

It would be appreciated if you could give me any suggestion.

Upvotes: 0

Views: 756

Answers (3)

nilatti
nilatti

Reputation: 578

I think your params should look like this:

def schedule_params
    params.require(:schedule).permit(
      :title, :departure_date, 
      rooms_attributes: [
        :id, :_destroy, :room, :room_address, :schedule_id, :day,  
        amounts_attributes: [ :id, :_destroy,
          :itinerary_id, :room_id, :event_id, :id, :_destroy, :ccy, :amount]
]
)
end

So, for your nested model, even if it's deeply nested, you still need :id and :_destroy.

Let me know how that goes for you.

Upvotes: 0

Nic Nilov
Nic Nilov

Reputation: 5155

Following from the logged params, your amounts_attributes is an array of objects and should be declared as such in your permit method argument:

def schedule_params
    params.require(:schedule).permit(
      :title, :departure_date, 
      rooms_attributes: [{
        :id, :_destroy, :room, :room_address, :schedule_id, :day,  
        amounts_attributes: [{
          :itinerary_id, :room_id, :event_id, :id, :_destroy, :ccy, :amount
        }]
      }]
    )
end

The rooms_attributes follows similar structure and needs to be corrected as well.

Take a look at the nested parameters example in ActionController::Parameters docs.

Upvotes: 0

Sravan
Sravan

Reputation: 18657

You haven't closed the room_attributes array parameter.Please close it and open the amount's attribute nested parameters. Also the schedule_id in amount's attributes.

def schedule_params
        params.require(:schedule).permit(:title, 
        :departure_date,{rooms_attributes: [:id, :_destroy, :room, :room_address, :schedule_id, :day,
        { amounts_attributes: [:itinerary_id, :room_id, :event_id, :id, :_destroy, :ccy, :amount]}
        ]}
        )
end 

Upvotes: 0

Related Questions