Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

building a has_one relation with devise user in rails

Im new to rails and am having difficulty creating a profile by a devise user

here is the ProfileController:

class ProfilesController < ApplicationController

  before_action :set_profile, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!

def index
 @profiles = Profile.all
end

def new
 @profile = current_user.build_profile
end

def create
@profile = current_user.build_profiles(profile_params)
redirect_to profiles_path
end

def show

end

def edit

end

def update
@profile.update(profile_params)
redirect_to(profiles_path(@profile))
end

def destroy
@profile.destroy
redirect_to profiles_path
end

private
def profile_params
params.require(:profile).permit(:university, :degree)
end

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

end

When i run the rails server i can submit the form but nothing is getting stored in the model 'Profile'

here is the index.html.erb where the data should appear:

<h2>profiles</h2>

<% @profiles.each do |profile| %>

  <%= link_to profile do %>
    <%= profile.university %>
  <% end %>
    <%= profile.degree %>

<% end %>

user.rb file:

has_one :profile

and the profile.rb file:

belongs_to :user

nothing seems to be getting saved to the profile model and nothing is getting displayed on the index.html.erb. Also i have created a migration to store user_id in the profile model.

Thank for your help

like image 738
Gurmukh Singh Avatar asked Oct 14 '25 03:10

Gurmukh Singh


1 Answers

By far the best way to create a profile for a user is to build it when the User object is created:

#app/models/user.rb
class User < ActiveRecord::Base
   has_one :profile
   before_create :build_profile
   accepts_nested_attributes_for :profile
end

#app/models/profile.rb
class Profile < ActiveRecord::Base
   belongs_to :user
end

This will build a blank profile each time a new user is created. It means that each user will only ever have one profile, which they'll be able to populate & edit.


In regards your issue, there are several points:

  1. Don't list "profiles" with an index, list users & pull their profile data
  2. If managing a profile, nest it under the associative user model

Here's how to do that:

# config/routes.rb
resources :users, only: :index
resource :profile, only: [:show, :update]

#app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController
   def show
   end

   def update
      redirect_to :show if current_user.update profile_params
   end

   private

   def profile_params
      params.require(:user).permit(profile_attributes: [:name])
   end
end

#app/views/profiles/show.html.erb
<%= form_for current_user, url: profile_path do |f| %>
   <%= f.fields_for :profile do |p| %>
      <%= p.text_field :name %>
   <% end %>
   <%= f.submit %>
<% end %>

Update

My post above is exactly what we do.

The way it works is very simple -- when a User is created (IE they have gone to the trouble of filling out their details), the Rails backend automatically creates a blank Profile object.

This does several things:

  1. Always makes sure you have a Profile for each user (you don't have to go to the bother of making them "create" a profile).

  2. Gives you the ability to validate only inputted data on a created Profile (not having to guess whether it's already been done).

--

If you're getting undefined method build_profile, it means your associations are incorrect.

All singular associations have build_[association] as defined instance methods. The code I provided fires build_profile for a has_one association. The only time it would be "undefined" would be if the association was plural

--

Update

enter image description here

This suggests a routing error.

Considering it appears at root, I think the problem is here:

#app/views/layouts/application.html.erb
<%= link_to "Profile", profile_path %>

You don't have edit_profile_path -- it should just be profile_path

like image 177
Richard Peck Avatar answered Oct 17 '25 21:10

Richard Peck