marg08 marg08 - 4 days ago 5
Ruby Question

Unable to associate User and Profile Model

I'm still relatively new to Ruby on Rails so I'm trying to figure this one out. I've done a lot of research so far but can't figure out how to tie it altogethe so that both my User & Profiles model associate with each other AND allow my Profile to save.
- I'm using the Devise gem, which registers a new user through the Registrations Controller.
- I have created a Profiles Controller.
- When a User registers, they are automatically brought to the Profile new.html.erb page to setup their profile. However, when I try to save it, nothing happens. However, if I remove the 'belongs_to :users' line of code under the ProfilesController, then I can save it without issue but it obviously doesn't associate it with the user.


  • I have created the relationship between the 2 models where a User should have only 1 profile. I've also created a user_id in the Profiles table to act as a foreign key to link the 2 tables.



My User model:

class User < ApplicationRecord

# Include default devise modules.
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable

has_one :profile, dependent: :destroy
accepts_nested_attributes_for :profile
end


My Profile model:

class Profile < ApplicationRecord
belongs_to :user
#after_create :create_profile
end


My Schema.

ActiveRecord::Schema.define(version: 20161126221219) do

create_table "profiles", force: :cascade do |t|
t.string "full_name"
t.string "contact_number"
t.string "location"
t.string "makeup_type"
t.string "bio"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "image"
end

create_table "users", force: :cascade do |t|
t.string "name", default: "", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end


My Profiles Controller:

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

def index
@search = Profile.search(params[:q])
@profiles = @search.result(distinct: true)
end

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

def new
@profile = Profile.new
end

def create
@profile = Profile.new(profile_params)

respond_to do |format|
if @profile.save
format.html { redirect_to @profile, notice: 'Your Profile was successfully created' }
format.json { render :show, status: :created, location: @profile }
else
format.html { render :new }
format.json { render json: @profile.errors, status: :unprocessable_entry }
end
end
end

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

def update
respond_to do |format|

if @profile.update(profile_params)
format.html { redirect_to @profile, notice: 'Profile was successfully updated.' }
format.json { render :show, status: :ok, location: @profile }
else
format.html { render :edit }
format.json { render json: @profile.errors, status: :unprocessable_entity }
end
end
end

def destroy
@profile.destroy

respond_to do |format|
format.html { redirect_to profile_url, notice: 'Profile was successfully destroyed.' }
format.json { head :no_content }
end
end

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

private
def profile_params
params.require(:profile).permit(:full_name, :contact_number, :location, :makeup_type, :bio, :user_id, :image)
end
end


I created a Users controller, which isn't created when setting up Devise but I wanted to override some of the actions. However, this is where I get stuck as I'm not sure what methods I'm supposed to override and how to do it as Devise is creating the user profile. Anyway, my User controller is below:

class UsersController < ApplicationController

def show
@user = User.find(params[:id])
end
end


Lastly, I created a RegistrationsController to override the Devise Registrations controller so I could route the registration page to the Profiles new.html.erb page below.

class RegistrationsController < Devise::RegistrationsController
# before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]

protected
# This allows a newly registered user to be directed to the Profile Creation page
def after_sign_up_path_for(resource)
new_profile_path(resource)
end

def after_sign_in_path_for(resource)
profile_path(resource)
end
end

Answer

You should use the current_user helper in the controller.

Instead of:

def profile_params
  params.require(:profile).permit(:full_name, :contact_number, :location, :makeup_type, :bio, :user_id, :image)
end   

You could use:

def profile_params
  params[:profile][:user_id] = current_user.id
  params.require(:profile).permit(:full_name, :contact_number, :location, :makeup_type, :bio, :user_id, :image)
end  

Also you should add a before_action, which makes sure that a current_user is present, otherwise you should redirect to the login page.

Comments