random_user_0891
random_user_0891

Reputation: 2071

rails 5.1: nested form validation

I have a parent model called user and 2 nested models called award and certification. when I go to save a certification the model validation for award tells me that awards is blank, and when I got to save an award I get an error that says the validations for certification is blank. not sure what's going on.

here my user model

  has_many :certifications, dependent: :destroy
  has_many :awards, dependent: :destroy


  # allows for nested attributes in the user views.
  accepts_nested_attributes_for :work_histories, :qualifications, :certifications, :courses, :awards,
  :languages, :patents, :publications, allow_destroy: true 

here my award model

    class Award < ApplicationRecord
  belongs_to :user

  validates :award_name, :award_granted_by, :award_date, :award_description, presence: true  

end

and my certification model

class Certification < ApplicationRecord
  belongs_to :user

  validates :certification_name, :certification_authority, :certification_number, :certification_from,
            :certification_to, presence: true

end

strong params in users_controller

 def user_params
   params.require(:user).permit( :first_name, :last_name, :email, :phone, :current_job_title, :password, :password_confirmation, 
   work_histories_attributes: [:user_id, :id, :_destroy, :job_title, :company, :description, :city, :state,:start_date, :end_date],
   qualifications_attributes: [:user_id, :id, :_destroy, :education, :university, :university_major, :graduation_year, :currently_enrolled, :location],
   awards_attributes: [:user_id, :id, :_destroy, :award_name, :award_granted_by, :award_date, :award_description],                            
   certifications_attributes: [:user_id, :id, :_destroy, :certification_name, :certification_authority, :certification_number, :certification_from, :certification_to, :cert_never_expires],                           
   courses_attributes: [:user_id, :id, :_destroy, :course_name, :course_number, :course_description],
   languages_attributes: [:user_id, :id, :_destroy, :language, :language_proficiency],
   patents_attributes: [:user_id, :id, :_destroy, :patent_title, :patent_office, :patent_number, :patent_status, :patent_date, :patent_description],
   publications_attributes: [:user_id, :id, :_destroy, :publication_title, :publication_source, :publication_date, :publication_description] )
 end   

here's a part of the User form. I've got a button dropdown that has several options, when a user selects an option that particular div will be shown with a modal window.

  <!-- one-to-many nested attributes -->  
  <%= form_for(@user) do |form| %>

      <!-- a partial is rendered based on the user dropdown selection -->    
      <div id="award">
        <%= render partial: "awards/new_award_modal", locals: { form: form } %>
      </div>  
      <div id="cert">
        <%= render partial: "certifications/new_certification_modal", locals: { form: form } %>
      </div>                    

    <%= form.submit 'Save', id: "submit-achievement", class: 'btn btn-primary form-control' %>

  </div><!-- modal body -->

    <div class="modal-footer">
      <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
    </div>

  <% end %><!-- form_for -->  

here is the partial for certifications

<div class="new_cert"> 

<%= form.fields_for :certifications, Certification.new do |cert_field| %>

  <div class="field">
    <%= cert_field.label :certification_name, 'Certification Title' %>
    <%= cert_field.text_field :certification_name, class: "form-control" %>       
  </div>
  <div class="field">
    <%= cert_field.label :certification_authority %>
    <%= cert_field.text_field :certification_authority, class: "form-control" %>       
  </div>
  <div class="field">
    <%= cert_field.label :certification_number %>
    <%= cert_field.text_field :certification_number, class: "form-control" %>       
  </div>

  <table>
    <tr>
      <td>
      <div class="field">
        <%= cert_field.label :certification_from, "From" %><br />
        <%= cert_field.date_select :certification_from,{ :order => [:day, :month, :year],
            :start_year => Date.current.year, :end_year => 1960,
            :prompt => {day: 'Day', month: 'Month', year: 'Year'}, :discard_day => true }, class: 'form-control' %>
      </div>     
      </td>
      <td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
      <td>
      <div class="field">
        <%= cert_field.label :certification_to, "To" %><br />
        <%= cert_field.date_select :certification_to, { :order => [:day, :month, :year], 
            :start_year => Date.current.year + (10), :end_year => 1960,
            :prompt => {day: 'Day', month: 'Month', year: 'Year'}, :discard_day => true }, class: 'form-control'  %>
      </div>        
      </td>
    </tr>
  </table>  

  <div>
    <%= cert_field.label :cert_never_expires, "This certification does not expire", class: "l" %>
    <%= cert_field.check_box :cert_never_expires, class: 'cb' %>
  </div>
  <br />

<% end %>

</div><!-- ./new_cert -->

here's the awards partial

<div class="new_award">

  <!-- nested attributes for award modal -->  
  <%= form.fields_for :awards, Award.new do |award_field| %>

      <div class="field">
        <%= award_field.label :award_name, 'Award or Honor Name' %>
        <%= award_field.text_field :award_name, class: "form-control" %>       
      </div>

      <div class="field">
        <%= award_field.label :award_granted_by, "Granted by" %>
        <%= award_field.text_field :award_granted_by, class: "form-control" %>       
      </div>

      <div class="field form-inline">
        <%= award_field.label :award_date, 'Date' %><br />
        <%= award_field.date_select :award_date, { :order => [:day, :month, :year],
            :start_year => Date.current.year, :end_year => 1960,
            :prompt => {day: 'Day', month: 'Month', year: 'Year'}, 
            :discard_day => true }, class: 'form-control ds' %>
      </div>     

      <div class="field">
        <%= award_field.label :award_description, 'Description' %>
        <%= award_field.text_area :award_description, class: "form-control" %>       
      </div>

  <% end %><!-- ./fields_for -->

</div>

so both awards and certifications can be saved to the database without any issue when there are no validations. however, when I just do a simple validation checking for presence of an attribute in the form that's when things get weird. The award model is saying that the certification form is empty, which it should be because I'm submitting the award form. And the opposite is also true, when I go to submit a certification the award validation is triggered saying the award form is blank.

Upvotes: 0

Views: 626

Answers (1)

Kara Carrell
Kara Carrell

Reputation: 78

It would be best to see the specific error you're getting, but I'd make sure that your form is setting the nested attributes appropriately, and that your user controller has nested attributes setup within the strong parameters.

There's documentation in the Rails guides: http://api.rubyonrails.org/classes/ActionController/StrongParameters.html

Upvotes: 1

Related Questions