Search code examples
ruby-on-railsruby-on-rails-5has-many-throughaccepts-nested-attributes

Rails 5: Nested attributes aren't updated for model


I can't get rails to update my nested attributes, though regular attributes work fine. This is my structure:

unit.rb:

class Unit < ApplicationRecord
  has_many :unit_skill_lists
  has_many :skill_lists, through: :unit_skill_lists, inverse_of: :units, autosave: true

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

unit_skill_list.rb:

class UnitSkillList < ApplicationRecord
  belongs_to :unit
  belongs_to :skill_list
end

skill_list.rb:

class SkillList < ApplicationRecord
  has_many :unit_skill_lists
  has_many :units, through: :unit_skill_lists, inverse_of: :skill_lists
end

And this is (part of) the controller:

class UnitsController < ApplicationController
  def update
    @unit = Unit.find(params[:id])

    if @unit.update(unit_params)
      redirect_to edit_unit_path(@unit), notice: "Unit updated"
    else
      redirect_to edit_unit_path(@unit), alert: "Unit update failed"
    end
  end

  private
    def unit_params
      unit_params = params.require(:unit).permit(
          ...
          skill_list_attributes: [:id, :name, :_destroy]
      )
      unit_params
    end
end

The relevant rows in the form (using formtastic and cocoon):

<%= label_tag :skill_lists %>
<%= f.input :skill_lists, :as => :check_boxes, collection: SkillList.where(skill_list_type: :base), class: "inline" %>

Any idea where I'm going wrong? I have tried following all guides I could find but updating does nothing for the nested attributes.

Edit after help from Vasilisa:
This is the error when I try to update a Unit:

ActiveRecord::RecordInvalid (Validation failed: Database must exist):

This is the full unit_skill_list.rb:

class UnitSkillList < ApplicationRecord
  belongs_to :unit
  belongs_to :skill_list
  belongs_to :database
end

There is no input field for "database". It is supposed to be set from a session variable when the unit is updated.


Solution

  • If you look at the server log you'll see something like skill_list_ids: [] in params hash. You don't need accepts_nested_attributes_for :skill_lists, since you don't create new SkillList on Unit create/update. Change permitted params to:

    def unit_params
      params.require(:unit).permit(
          ...
          skill_list_ids: []
      )
    end
    

    UPDATE

    I think the best options here is to set optional parameter - belongs_to :database, optional: true. And update it in the controller manually.

    def update
      @unit = Unit.find(params[:id])
      if @unit.update(unit_params)
        @unit.skill_lists.update_all(database: session[:database])
        redirect_to edit_unit_path(@unit), notice: "Unit updated"
      else
        redirect_to edit_unit_path(@unit), alert: "Unit update failed"
      end
    end