RuNpiXelruN RuNpiXelruN - 5 months ago 18
Ruby Question

Rails ActiveRecord not finding correct user

I'm building an app in which a user

has_one :profile
and a profile
belongs_to :user
but am scratching my head as to why it is looking for the
user_id
and not the
profile_id
when i'm on the profile show page. The error i'm getting is

Couldn't find User with 'id'=15

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


I have some polymorphic relationships going on with a Subject model. A profile can have many subjects and basically on the subject show page i want to link up the user that created the subject, and click to go to that user's profile page. Sorry if that was hard to understand, please find the code below.

users_controller.rb



class UsersController < ApplicationController
include UserCreateHelper

skip_before_action :require_login, only: [:new, :create], raise: false

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

def new
@user = User.new
end

def create
@user = sign_up(user_params)

if @user.valid?
sign_in(@user)
create_user_profile(current_user)
redirect_to profile_path(current_user)
else
render :new
end
end

private

def user_params
params.require(:user).permit(:email, :password)
end
end


Here I am creating an instance of a profile on user signup and redirecting to their new profile page to fill in their details. This step works fine.

profiles_controller.rb



class ProfilesController < ApplicationController

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

def update
if @profile = current_user.profile
@profile.update(profile_params)
redirect_to profile_path(current_user)
end
end


private
def profile_params
params.require(:profile).permit(:bio, :user_id)
end
end


The profiles show method above is the one creating the issue.

views/profiles/show.html.erb



<div>
<p>Hi <%= @user.email %></p>
<% if @profile.bio %>
<hr>
<p><%= @profile.bio %></p>
<% else %>
<p>Fill out the rest of your profile!</p>
<%= render partial: 'profiles/form', locals: {type: @profile} %>
<% end %>
</div>
<hr>
<%= render partial: 'subjects/subject', locals: {subjectable: @profile} %>
<%= render partial: 'subjects/form', locals: {subjectable: @profile} %>
<%= render partial: 'locations/location', locals: {locationable: @profile} %>
<%= render partial: 'locations/form', locals: {locationable: @profile} %>


The above polymorphic associations work fine if in the profiles controller show I remove
@user = User.find(params[:id])
(i have also tried changing it to params[:user_id]) but to no avail. As i said, removing this line allows me to add the subjects fine, signup as another user and again add subjects fine, on the subjects index/all_subjects page list the subjects fine also, but when i try to link up the user who created the subject to go to their profile page it fails.

views/subjects/all_subjects.html.erb



<% @all_subjects.each do |subject| %>
<p><%= subject.title %> | Created by <%= link_to subject.user.email, profile_path(subject.user) %>, <%= time_ago_in_words(subject.created_at) + ' ago' %></p>
<% end %>


I know that's long winded but any help would be greatly appreciated. I'm happy to link the github repos if it would help.

schema.rb



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

create_table "locations", force: :cascade do |t|
t.integer "user_id"
t.string "locationable_type"
t.integer "locationable_id"
t.string "suburb"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["locationable_type", "locationable_id"], name: "index_locations_on_locationable_type_and_locationable_id"
t.index ["user_id"], name: "index_locations_on_user_id"
end

create_table "profiles", force: :cascade do |t|
t.integer "user_id"
t.text "bio"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_profiles_on_user_id"
end

create_table "subjects", force: :cascade do |t|
t.integer "user_id"
t.string "title"
t.text "description"
t.string "subjectable_type"
t.integer "subjectable_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["subjectable_type", "subjectable_id"], name: "index_subjects_on_subjectable_type_and_subjectable_id"
t.index ["user_id"], name: "index_subjects_on_user_id"
end

create_table "users", force: :cascade do |t|
t.string "email", null: false
t.string "password_digest", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
end

end

Answer

You're misusing Rails' link helpers. This line...

profile_path(subject.user) 

Needs to read

profile_path(subject.user.profile) 

The profile_path helper expects its argument to be a profile, not a user. It's using the ID of the user record, for which there is no matching profile ID, hence your "user not found" error.

On the other side of things, you shouldn't be doing this in your Profiles controller:

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

If anything, you should be doing the opposite:

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

In the context of the profiles controller, params[:id] will be the ID of a profile record, not a user record.

Comments