Rails simple_form - Nested Form NoMethodError in "show" page

347 views Asked by At

Im having some difficulty with making a nested form to work using simple_form, specifically with the show page. I have a Profile and Experience model, and would like to nest the Experience model within the Profile model. I believe I have set up the form file and controller and associations correctly, and the form seems to work fine, except when I try to save the form and go to the show page, I am getting the following error with regards to the feilds relating to my Experience model:

NoMethodError in Profiles#show

Showing c:/Users/Rashed/Desktop/Ministry-Web-Application (new)/app/views/profiles/show.html.erb where line #17 raised:

undefined method `company' for nil:NilClass

The issue seems to be with my code on the show page to render the nested Experience fields, however I cant seem to figure out how to solve the issue, despite searching for ages for a solution.

here is the code for my project:

show.html.erb:

<div class="row">
    <div class="col-md-offset-1 col-md-8">
        <p id="notice"><%= notice %></p>


        <p><strong>Full Name:</strong>&nbsp;&nbsp;<%= @profile.name %></p>
        <p><strong>Civil ID no:</strong>&nbsp;&nbsp;<%= @profile.civil %></p>
        <p><strong>Date of Employment:</strong>&nbsp;&nbsp;<%= @profile.date_of_employment %></p>
        <p><strong>Mobile no:</strong>&nbsp;&nbsp;<%= @profile.mobile %></p>
        <p><strong>Work Email:</strong>&nbsp;&nbsp;<%= @profile.work_email %></p>
        <p><strong>Personal Email</strong>&nbsp;&nbsp;<%= @profile.personal_email %></p>
        <p><strong>Internal no:</strong>&nbsp;&nbsp;<%= @profile.internal_no %></p>
        <p><strong>Nationality:</strong>&nbsp;&nbsp;<%= @profile.nationality %></p>
        <p><strong>Gender:</strong>&nbsp;&nbsp;<%= @profile.gender %></p>
        <p><strong>Academic Degree:</strong>&nbsp;&nbsp;<%= @profile.academic_degree %></p>
        <p><strong>Major:</strong>&nbsp;&nbsp;<%= @profile.major %></p>

        <p><strong>Company / Workplace</strong>&nbsp;&nbsp;<%= @experience.company %></p>
        <p><strong>Company / Workplace</strong>&nbsp;&nbsp;<%= @experience.period_of_employment %></p>
    <p><strong>Company / Workplace</strong>&nbsp;&nbsp;<%= @experience.title %></p>


        <%= link_to 'Edit', edit_profile_path(@profile) %> |
        <%= link_to 'Back', profiles_path %>
    </div>
</div>

profiles_controller.rb

class ProfilesController < ApplicationController
  before_action :set_profile, only: [:show, :edit, :update, :destroy]

  respond_to :html

  def index
    @profiles = Profile.all
    respond_with(@profiles)
  end

  def show
    respond_with(@profile)
  end

  def new
    @profile = Profile.new
    @profile.experiences.build
    respond_with(@profile)
  end

  def edit
  end

  def create
    @profile = Profile.new(profile_params)
    @profile.user_id = current_user.id
    @profile.save
    respond_with(@profile)
  end

  def update
    @profile.update(profile_params)
    respond_with(@profile)
  end

  def destroy
    @profile.destroy
    respond_with(@profile)
  end

  private
    def set_profile
      @profile = Profile.find(params[:id])
    end

    def profile_params
      params.require(:profile).permit(:name, :civil, :date_of_employment, :mobile, :work_email, :personal_email, :internal_no, :nationality, :gender, :academic_degree, :major, :work_experience, experiences_attributes: [:company, :period_of_employment, :title])
    end
end

_form.html.erb

<%= simple_form_for(@profile) do |f| %>
  <%= f.error_notification %>

  <div class="form-inputs">
    <%= f.input :name, label: 'Full Name:' %>
    <%= f.input :civil, label: 'Civil ID:' %>
    <%= f.input :gender, collection: ['Male', 'Female'], label: 'Gender:', as: :radio_buttons, :include_blank => false %>
    <%= f.input :date_of_employment, label: 'Date of Employement:', as: :date, start_year: Date.today.year - 50, end_year: Date.today.year, order: [:day, :month, :year], input_html: { class: 'inline-date' } %>
    <%= f.input :mobile, label: 'Mobile no:' %>
    <%= f.input :work_email, label: 'Work Email:' %>
    <%= f.input :personal_email, label: 'Personal Email:' %>
    <%= f.input :internal_no, label: 'Internal no:' %>
    <%= f.input :nationality, collection: ['Kuwaiti', 'Non-Kuwaiti'], label: 'Nationality:', as: :radio_buttons, :include_blank => false %>
    <%= f.input :academic_degree, collection: ["Pre-Bachelor's Degree", "Diploma", "Bachelor's Degree", "Master's Degree", "Ph.D"], label: 'Academic Degree', as: :select, :include_blank => 'Choose Your Degree...' %>
    <%= f.input :major, collection: ["Architecture", "Civil Engineering", "Mechanical Engineering", "Chemical Engineering", "Computer Engineering", "Interior Designer", "Electrical Engineering", "Civil Engineering / Structure", "Administration"], label: 'Major', as: :select, :include_blank => 'Choose Your Major...' %>
    <%= f.input :nationality, collection: ['Kuwaiti', 'Non-Kuwaiti'], label: 'Nationality:', as: :radio_buttons, :include_blank => false %>
    <%= f.input :work_experience, collection: ['No', 'Yes'], label: 'Previous Work Experience?', as: :radio_buttons, :include_blank => false %>

    <%= f.simple_fields_for :experiences, Experience.new do |builder| %>
        <%= buidler.input :company %>
    <%= buidler.input :period_of_employment, label: 'Period of Employement:', as: :date, start_year: Date.today.year - 50, end_year: Date.today.year, order: [:day, :month, :year], input_html: { class: 'inline-date' } %>
    <%= builder.input :title, label: 'Job Title' %>
      <% end %>


  </div>

  <div class="form-actions">
    <%= f.button :submit %>
  </div>
<% end %>

Experience Model:

class Experience < ActiveRecord::Base

    belongs_to :profile 

end

Profile Model:

class Profile < ActiveRecord::Base

    belongs_to :users
    has_many :experiences

    accepts_nested_attributes_for :experiences


end

Thanks in advance!

2

There are 2 answers

0
Mandeep On BEST ANSWER

Each Profile has many Experiences so when you do @profile.experiences, it returns a collection and not a single record. You need to iterate over these and show them like this:

<% @profile.experiences.each do |experience| do %>
  <p><strong>Company / Workplace</strong>&nbsp;&nbsp;<%= experience.company %></p>
  <p><strong>Company / Workplace</strong>&nbsp;&nbsp;<%= experience.period_of_employment %></p>
  <p><strong>Company / Workplace</strong>&nbsp;&nbsp;<%= experience.title %></p>
<% end %>
0
Prashant4224 On

Could you try this

<div class="row">
  <div class="col-md-offset-1 col-md-8">
    <p id="notice"><%= notice %></p>
    <p><strong>Full Name:</strong>&nbsp;&nbsp;<%= @profile.name %></p>
    <p><strong>Civil ID no:</strong>&nbsp;&nbsp;<%= @profile.civil %></p>
    <p><strong>Date of Employment:</strong>&nbsp;&nbsp;<%= @profile.date_of_employment %></p>
    <p><strong>Mobile no:</strong>&nbsp;&nbsp;<%= @profile.mobile %></p>
    <p><strong>Work Email:</strong>&nbsp;&nbsp;<%= @profile.work_email %></p>
    <p><strong>Personal Email</strong>&nbsp;&nbsp;<%= @profile.personal_email %></p>
    <p><strong>Internal no:</strong>&nbsp;&nbsp;<%= @profile.internal_no %></p>
    <p><strong>Nationality:</strong>&nbsp;&nbsp;<%= @profile.nationality %></p>
    <p><strong>Gender:</strong>&nbsp;&nbsp;<%= @profile.gender %></p>
    <p><strong>Academic Degree:</strong>&nbsp;&nbsp;<%= @profile.academic_degree %></p>
    <p><strong>Major:</strong>&nbsp;&nbsp;<%= @profile.major %></p>
    <% @profile.experiences.each do |experience| %>
      <p><strong>Company / Workplace</strong>&nbsp;&nbsp;<%= experience.try(:company) %></p>
      <p><strong>Company / Workplace</strong>&nbsp;&nbsp;<%= experience.try(:period_of_employment) %></p>
      <p><strong>Company / Workplace</strong>&nbsp;&nbsp;<%= experience.try(:title) %></p>
    <% end %>
    <%= link_to 'Edit', edit_profile_path(@profile) %> |
    <%= link_to 'Back', profiles_path %>
</div>

Hope it helps!