Home > database >  Rails Issue with submitting form when adding nested form
Rails Issue with submitting form when adding nested form

Time:02-17

A Rails newbie here. I believe I am rather confused as to how fields_for operates within a rails form. I have a has many through relationship formed with Projects, Organizations, and Affiliations in the middle. A Project can have many Organizations, and an Organization can have many Projects. Affiliations is in the middle with a :role attribute that is meant to be edited to show what role an Organization plays within a Project. I was able to get the functionality of adding many Organizations to a Project working just fine. I utilized chosen-rails to implement a neat UI to select multiple, search, etc. I can add and remove Organizations to a Project just fine with that. However, upon trying to implement some way to manipulate the role each Organization plays in a Project through altering the role attribute with a fields_for form, submissions of the original form break. I have tried many variations of the fields_form, including one from a guide here.

In project.rb:

def affiliations_attributes=(affiliations_attributes)
  affiliations_attributes.each do |i, affiliation_attributes|
    if affiliation_attributes[:role].length > 0
        self.affiliations.build(affiliation_attributes)
    end
  end
end

In the project form:

<%= f.fields_for :affiliations do |affiliation_builder|%>
    <%= affiliation_builder.label :role %>
    <%= affiliation_builder.text_field :role %>
<% end %>

With this setup, on submission of the form, I receive an error stating that 'Affiliations organization must exist.' I don't understand why, since I'm not even editing the Affiliations or Organization here. Is there something I am missing?

Prior to this, I tried doing this for a fields_for form:

<%= f.fields_for :affiliations do |affiliation|%>
  <%= affiliation.label :role, ("Role in Project") %>
  <%= affiliation.text_field :role, autofocus: true, autocomplete: 'off', placeholder: 'e.g. Donor, Founder', class: 'form-control' %>
<% end %>

Projects Controller:

def project_params
   params.require(:project).permit(:organization, {organization_ids: []}, 
   :stream_name, :implementation_date, :narrative,
   :length, :primary_contact,:number_of_structures, :structure_description, 
   :name, affiliations_attributes: [:id, :role], photos: [])
end

Now, surprisingly, this works when updating the role attribute in Affiliations. I can also add Organizations to the project with no issue, and add subsequent roles to the created Affiliation. However, the problem arises when I try to remove an Organization. Rails flashes an ActiveRecord::RecordNotFound in ProjectsController#update error stating "Couldn't find Affiliation with ID= for Project with ID=". I have no idea what is going on here and have been banging my head against the wall for a couple days now trying to fix this. The only thing I can think is somehow there's an ID matching issue, or some parameter not being properly passed. One thing I did notice when toying around with the project_params on the second method above and removing :id from affiliations_attributes is that I get flashed with the same error message about an 'Affiliations organization' being required. Perhaps there's some way to pass an organization ID with the affiliation_builder method? Any help or guidance would be greatly appreciated here. Thank you.

class Affiliation < ApplicationRecord
  belongs_to :project
  belongs_to :organization
end

class Organization < ApplicationRecord

  has_many :affiliations
  has_many :projects, through: :affiliations

end

class Project < ApplicationRecord

  has_many :affiliations
  has_many :organizations, through: :affiliations
  accepts_nested_attributes_for :affiliations

  def affiliations_attributes=(affiliations_attributes)
    affiliations_attributes.each do |i, affiliation_attributes|
      if affiliation_attributes[:role].length > 0
        self.affiliations.build(affiliation_attributes)
      end
    end
  end
end

CodePudding user response:

Why |i, affiliation_attributes| ? use |affiliation_attributes|

CodePudding user response:

I believe I have found a solution, though I am not sure if it is technically correct. I looked at the order of the attributes being pushed when Project was updated, and I noticed that organization_ids was being pushed in the Hash before affiliations_attributes. So I think it was trying to update something that just didn't exist, and was giving some misleading information (at least to me). I was able to fix this issue by forcing the affiliations_attributes to be pushed first in a separate update by itself, and then pushing the rest of the project attributes in the main update.

  def project_organization_params
     params.require(:project).permit(:id, {affiliations_attributes: [:id, 
     :role]})
  end

And then update with:

@project = Project.find(params[:id])
@project.update(project_organization_params)

if @project.update(project_params)
...

Everything seems to be working just fine now.

  • Related