Reputation: 15
so the problem is that when i create a user profile it takes user input correctly and displays it on view but when I edit it, it goes to the edit page and after click on submit it gives an error
TypeError in Profiles#show Showing /home/nouman/GitConnect/app/views/profiles/show.html.erb where line #22 raised:
no implicit conversion of String into Integer Extracted source (around line #22): <% @profile.education.each do |edu| %>
<% if edu["degree"].present? %> Degree: <%= edu["degree"] %> <% else %> Degree: Not provided
I'm using a partial for new
this is _form.html.erb
<%= form_with(model: @profile, local: true) do |form| %>
<% if @profile.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@profile.errors.count, "error") %> prohibited this profile from being saved:</h2>
<ul>
<% @profile.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :profile_pic %>
<%= form.file_field :profile_pic %>
</div>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name, required: true %>
</div>
<div class="field">
<%= form.label :email %>
<%= form.email_field :email, optional: true %>
</div>
<div class="field">
<%= form.label :contact_info %>
<%= form.text_field :contact_info %>
</div>
<div class="field">
<%= form.label :headline %>
<%= form.text_field :headline %>
</div>
<div class="field">
<%= form.label :city %>
<%= form.text_field :city %>
</div>
<div class="field">
<%= form.label :social_media_links %>
<%= form.text_field :social_media_links, placeholder: 'Link 1', value: @profile.social_media_links[0] %>
<%= form.text_field :social_media_links, placeholder: 'Link 2', value: @profile.social_media_links[1] %>
<%= form.text_field :social_media_links, placeholder: 'Link 3', value: @profile.social_media_links[2] %>
</div>
<div class="field">
<%= form.label :education, "Education" %>
<div class="education-entry">
<%= form.label :degree, "Degree" %>
<%= form.text_field :education, name: "profile[education][][degree]", placeholder: "Enter degree" %>
<%= form.label :institution, "Institution" %>
<%= form.text_field :education, name: "profile[education][][institution]", placeholder: "Enter institution" %>
<%= form.label :graduation_date, "Graduation Date" %>
<%= form.date_select :graduation_date, name: "profile[education][][graduation_date]" %>
</div>
<div class="education-entry">
<%= form.label :degree, "Degree" %>
<%= form.text_field :education, name: "profile[education][][degree]", placeholder: "Enter degree" %>
<%= form.label :institution, "Institution" %>
<%= form.text_field :education, name: "profile[education][][institution]", placeholder: "Enter institution" %>
<%= form.label :graduation_date, "Graduation Date" %>
<%= form.date_select :graduation_date, name: "profile[education][][graduation_date]" %>
</div>
</div>
<div class="field">
<%= form.label :work_experience, "Work Experience" %>
<div class="work-entry">
<%= form.label :position, "Position" %>
<%= form.text_field :work_experience, name: "profile[work_experience][][position]", placeholder: "Enter position" %>
<%= form.label :company, "Company" %>
<%= form.text_field :work_experience, name: "profile[work_experience][][company]", placeholder: "Enter company" %>
<%= form.label :start_date, "Starting Date" %>
<%= form.date_select :start_date, name: "profile[work_experience][][start_date]", placeholder: "Enter Starting date" %>
<%= form.label :end_date, "Ending Date" %>
<%= form.date_select :end_date, name: "profile[work_experience][][end_date]", placeholder: "Enter Ending date" %>
</div>
<div class="work-entry">
<%= form.label :position, "Position" %>
<%= form.text_field :work_experience, name: "profile[work_experience][][position]", placeholder: "Enter position" %>
<%= form.label :company, "Company" %>
<%= form.text_field :work_experience, name: "profile[work_experience][][company]", placeholder: "Enter company" %>
<%= form.label :start_date, "Starting Date" %>
<%= form.date_select :start_date, name: "profile[work_experience][][start_date]", placeholder: "Enter Starting date" %>
<%= form.label :end_date, "Ending Date" %>
<%= form.date_select :end_date, name: "profile[work_experience][][end_date]", placeholder: "Enter Ending date" %>
</div>
</div>
<div class="actions">
<%= form.submit %>
</div>
<%
end %>
edit.html.erb
<h1>Edit Your Profile</h1>
<%= form_with(model: @profile, local: true) do |form| %>
<% if @profile.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@profile.errors.count, "error") %> prohibited this profile from being saved:</h2>
<ul>
<% @profile.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name, required: true %>
</div>
<div class="field">
<%= form.label :email %>
<%= form.email_field :email, optional: true %>
</div>
<div class="field">
<%= form.label :contact_info %>
<%= form.text_field :contact_info %>
</div>
<div class="field">
<%= form.label :profile_pic %>
<%= form.file_field :profile_pic %>
</div>
<div class="field">
<%= form.label :headline %>
<%= form.text_field :headline %>
</div>
<div class="field">
<%= form.label :city %>
<%= form.text_field :city %>
</div>
<div class="field">
<%= form.label :social_media_links %>
<%= form.text_field :social_media_links, placeholder: 'Link 1', name: "profile[social_media_links][]", value: @profile.social_media_links[0] %>
<%= form.text_field :social_media_links, placeholder: 'Link 2', name: "profile[social_media_links][]", value: @profile.social_media_links[1] %>
<%= form.text_field :social_media_links, placeholder: 'Link 3', name: "profile[social_media_links][]", value: @profile.social_media_links[2] %>
</div>
<div class="field">
<%= form.label :education, "Education" %>
<% @profile.education.each_with_index do |edu, index| %>
<div class="education-entry">
<%= form.label "education[#{index}][degree]", "Degree" %>
<%= form.text_field "education[#{index}][degree]", value: edu["degree"], placeholder: "Enter degree" %>
<%= form.label "education[#{index}][institution]", "Institution" %>
<%= form.text_field "education[#{index}][institution]", value: edu["institution"], placeholder: "Enter institution" %>
<%= form.label "education[#{index}][graduation_date]", "Graduation Date" %>
<%= form.date_select "education[#{index}][graduation_date]", selected: edu["graduation_date"] %>
</div>
<% end %>
</div>
<div class="field">
<%= form.label :work_experience, "Work Experience" %>
<% @profile.work_experience.each_with_index do |exp, index| %>
<div class="work-entry">
<%= form.label "work_experience[#{index}][position]", "Position" %>
<%= form.text_field "work_experience[#{index}][position]", value: exp["position"], placeholder: "e.g. Developer" %>
<%= form.label "work_experience[#{index}][company]", "Company" %>
<%= form.text_field "work_experience[#{index}][company]", value: exp["company"], placeholder: "e.g. Company A" %>
<%= form.label "work_experience[#{index}][duration]", "Duration" %>
<%= form.text_field "work_experience[#{index}][duration]", value: exp["duration"], placeholder: "e.g. 2020-2022" %>
</div>
<% end %>
</div>
<div class="actions">
<%= form.submit "Update Profile" %>
</div>
<% end %>
show.html.erb
<h1>Hello <%[email protected]%></h1>
<p><strong>Email:</strong> <%= current_user.email || 'Not provided' %></p>
<p><strong>Contact Info:</strong> <%= @profile.contact_info || 'Not provided' %></p>
<p><strong>City:</strong> <%= @profile.city || 'Not provided' %></p>
<p><strong>Headline:</strong> <%= @profile.headline || 'Not provided' %></p>
<p><strong>Profile Picture:</strong></p>
<% if @profile.profile_pic.present? %>
<%= image_tag @profile.profile_pic.url %>
<% else %>
<p>No profile picture uploaded.</p>
<% end %>
<h2>Social Media Links</h2>
<ul>
<% @profile.social_media_links.each do |link| %>
<li><%= link.present? ? link : 'Not provided' %></li>
<% end %>
</ul>
<h2>Education</h2>
<ul>
<% @profile.education.each do |edu| %>
<li>
<% if edu["degree"].present? %>
<strong>Degree:</strong> <%= edu["degree"] %>
<% else %>
<strong>Degree:</strong> Not provided
<% end %>
<% if edu["institution"].present? %>
<strong>Institution:</strong> <%= edu["institution"] %>
<% else %>
<strong>Institution:</strong> Not provided
<% end %>
<% if edu["graduation_date"].present? %>
<strong>Graduation Date:</strong> <%= edu["graduation_date"] %>
<% else %>
<strong>Graduation Date:</strong> Not provided
<% end %>
</li>
<% end %>
</ul>
<h2>Work Experience</h2>
<ul>
<% @profile.work_experience.each do |exp| %>
<li>
<% if exp["position"].present? %>
<strong>Position:</strong> <%= exp["position"] %>
<% else %>
<strong>Position:</strong> Not provided
<% end %>
<% if exp["company"].present? %>
<strong>Company:</strong> <%= exp["company"] %>
<% else %>
<strong>Company:</strong> Not provided
<% end %>
<% if exp["start_date"].present? %>
<strong>Start Date:</strong> <%= exp["start_date"] %>
<% else %>
<strong>Start Date:</strong> Not provided
<% end %>
<% if exp["end_date"].present? %>
<strong>End Date:</strong> <%= exp["end_date"] %>
<% else %>
<strong>End Date:</strong> Not provided
<% end %>
</li>
<% end %>
</ul>
<%= link_to 'Edit Profile', edit_profile_path(@profile) %>
profile_controller.html.erb
class ProfilesController < ApplicationController
before_action :authenticate_user!, except: [:index]
before_action :set_profile, only: %i[edit update destroy]
def show
@profile = current_user.profile
return unless @profile.nil?
redirect_to new_profile_path, alert: 'Please create your profile Frist'
end
def new
@profile = Profile.new
end
def create
@profile = current_user.build_profile(profile_params)
if @profile.save
redirect_to @profile, notice: 'Profile was successfully created.'
else
render :new, status: :unprocessable_entity
end
end
def edit; end
def update
if @profile.update(profile_params)
redirect_to @profile, notice: 'Profile was successfully updated.'
else
render :edit, status: :unprocessable_entity
end
end
private
def profile_params
params.require(:profile).permit(:name, :email, :contact_info, :profile_pic, :headline, :city,
social_media_links: %i[link1 link2 link3], education: %i[degree institution graduation_date], work_experience: %i[company position start_date end_date])
end
def set_profile
@profile = current_user.profile
redirect_to new_profile_path, alert: 'Profile not found. Please create a profile.' unless @profile
end
end
schema.rb
create_table "profiles", force: :cascade do |t|
t.string "name", null: false
t.string "email", null: false
t.string "profile_pic"
t.string "contact_info"
t.string "headline"
t.string "city"
t.integer "years_of_experience"
t.json "skill_sets", default: []
t.json "social_media_links", default: []
t.json "education", default: []
t.json "work_experience", default: []
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_profiles_on_user_id"
end
and there's a thing after it created it db it shows like
[#<Profile:0x00007f2fb965f1e0
id: 18,
name: "Nouman",
email: "[email protected]",
profile_pic: nil,
contact_info: "030700",
headline: "This is a developer profile",
city: "lahore",
years_of_experience: nil,
skill_sets: [],
social_media_links: [],
education: [{"degree"=>"BSSE", "institution"=>"Punjab College"}, {"degree"=>"Intermediate", "institution"=>"Punjab College"}],
work_experience: [{"company"=>"IIFA Tech", "position"=>"Intern"}, {"company"=>"Recurso Labs", "position"=>"Intern"}],
user_id: 15,
created_at: Fri, 04 Oct 2024 08:21:48.885126000 UTC +00:00,
updated_at: Fri, 04 Oct 2024 08:21:48.885126000 UTC +00:00>]
but when I edit it it changes it to
[#<Profile:0x00007f2fb96fe920
id: 18,
name: "Nouman",
email: "[email protected]",
profile_pic: nil,
contact_info: "030700",
headline: "This is a developer profile",
city: "lahore",
years_of_experience: nil,
skill_sets: [],
social_media_links: [],
education:
{"0"=>{"degree"=>"BSCS", "institution"=>"COMSATS"}, "1"=>{"degree"=>"Intermediate", "institution"=>"Punjab College"}},
work_experience: {"0"=>{"company"=>"IIFA ", "position"=>"Developers"}, "1"=>{"company"=>"Recurso Labs", "position"=>"Intern"}},
user_id: 15,
created_at: Fri, 04 Oct 2024 08:21:48.885126000 UTC +00:00,
updated_at: Fri, 04 Oct 2024 08:23:16.639720000 UTC +00:00>]
Upvotes: 0
Views: 69
Reputation: 102250
The core problem here really is that you painted yourself into a corner with a common rookie mistake which is thinking that if you have an array of stuff in your application you should be stuffing an array of stuff into your database. But that's not how relational databases work - or at least not how you should actually be using them.
Arrays type columns are a useful tool for a very limited set of specialized cases (read: almost never) but should not be the go to way for how you structure your data in a relational database. Especially not if you're using an array column to store serialized hashes which is in itself a really bad idea. The same applies to other structured data types such as JSON/JSONB/hstore.
Instead each row should contain one single set of values and you should use separate tables to store related entities. This is whats known as first normal form and is a pretty core tenant of good database design.
For example you should create a separate table for educations:
class Profile < ApplicationRecord
has_many :educations
end
# rails g model education profile:references degree:string institute:string graduation_date:date
class Education < ApplicationRecord
belongs_to :profile
end
This uses a one to many assocation but the assocation could also be many to many if you want to avoid duplication.
This lets you actually normalize the attributes of that table and not make a complete mess. It also lets you utilize the features that Rails provide for creating nested models:
class Profile < ApplicationRecord
has_many :educations
accepts_nested_attributes_for :educations
end
<%= form_with(model: @profile) do |form| %>
# ... other fields
<%= form.fields_for(:educations) do |education_fields| %>
<div class="education">
<div class="field">
<%= education_fields.label :degree %>
<%= education_fields.text_field :degree %>
</div>
<div class="field">
<%= education_fields.label :institute %>
<%= education_fields.text_field :institute %>
</div>
<div class="field">
<%= education_fields.label :graduation_date %>
<%= education_fields.date_field :graduation_date %>
</div>
</div>
<% end %>
# ...
<% end %>
class ProfilesController < ApplicationController
before_action :authenticate_user!, except: [:index]
before_action :set_profile, only: %i[edit update destroy]
# ...
def new
@profile = Profile.new
3.times { @profile.educations.new } # seeds the fields on the form
end
private
def profile_params
# Line breaks are free. Keep your line lengths readible.
params.require(:profile)
.permit(
# ...
educations_attributes: %i[degree institution graduation_date],
# ...
)
end
# ...
end
You then need to repeat this process for the other relations. Yes, it does mean that you have to take a step back and redo your work but it will pay off immensely.
See:
Upvotes: 1