Search code examples
ruby-on-railssimple-formcocoon-gem

3rd level nested model not receiving grandparent ID in form


I have a 3 models. User, CV, and Language. A User has one CV. A CV has many Languages. The User has many Languages through its CV. When I try to save the form I get an error that the Language does not have a User ID. How can I get the User ID to pass through the CV and to the Language in my form?

The CV is receiving the User ID properly. Languages is not.

I am using the Simple-Form and Cocoon gems.

Simplified version of form

= simple_form_for(@cv, url: user_cvs_path) do |f|
    = f.simple_fields_for :languages do |language|

From User Model

has_one :cv, dependent: :destroy
has_many :languages, through: :cv, inverse_of: :user

From Cv Model

belongs_to :user
has_many :languages, dependent: :destroy
accepts_nested_attributes_for :languages, allow_destroy: true

From Language Model

belongs_to :user
belongs_to :cv

From the CV Controller

before_action :set_user
def new
  @cv = @user.build_cv
  @cv.languages.build
end
def create
  @cv = @user.create_cv(cv_params)
  respond_to do |format|
    if @cv.save
      format.html { redirect_to user_cv_url(@user, @cv), notice: 'Cv was successfully created.' }
      format.json { render :show, status: :created, location: @cv }
    else
      format.html { render :new }
      format.json { render json: @cv.errors, status: :unprocessable_entity }
    end
  end
end
def cv_params
  params.require(:cv).permit(
    :user_id,
    :first_name,
    :middle_name,
    :last_name,
    ... # lots of params left out for brevity
    languages_attributes: [
      :id,
      :cv_id,
      :user_id,
      :name,
      :read,
      :write,
      :speak,
      :listen,
      :_destroy])
end
def set_user
  @user = current_user if user_signed_in?
end

Solution

  • Your Language model does not need the belongs_to :user. Language belongs to CV and CV belongs to User, so the relation between Language and User is already in place. If you need to access the user for a specific language you can write @language.cv.user

    To solve your problem just remove the belongs_to :user from the Language model, remove the user_id from languages_attributes, and remove the user_id from languages table.