JLBaguio
JLBaguio

Reputation: 13

Connecting a User(devise) to their Profile

I am using Devise and am trying to allow each User to create 1 Profile. I am able to send the the newly registered User to the page where they can create a Profile, but once the User logs out and back in it will not go to the Profile Show page.

In other words-

I can sign up a new User and send the User to the Create Profile page, then I can create a Profile with the new User(I am not sure the Profile is saving correctly)... After I log out and sign in I recieved the error:

ActiveRecord::RecordNotFound in ProfilesController#show

Couldn't find Profile without an ID

I would like the User to be sent to their Profile Show page...

Any thoughts on the issue?

The code (sorted by files) is below…

user.rb

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
     :recoverable, :rememberable, :trackable, :validatable

  attr_accessible :email, :password, :password_confirmation, :remember_me

 has_one :profile
end

profile.rb

class Profile < ActiveRecord::Base
 attr_accessible :first_name, :last_name

 belongs_to :user

end

profiles_controller.rb

class ProfilesController < ApplicationController
 # GET /profiles
 # GET /profiles.json
def index
 @profiles = Profile.all

respond_to do |format|
  format.html # index.html.erb
  format.json { render json: @profiles }
 end
end

# GET /profiles/1
# GET /profiles/1.json
def show
 @profile = Profile.find(params[:id])

 respond_to do |format|
  format.html # show.html.erb
  format.json { render json: @profile }
 end
end

# GET /profiles/new
# GET /profiles/new.json
def new
 @profile = Profile.new

 respond_to do |format|
  format.html # new.html.erb
  format.json { render json: @profile }
 end
end

# GET /profiles/1/edit
def edit
 @profile = Profile.find(params[:id])
end

# POST /profiles
# POST /profiles.json
def create
  @profile = Profile.new(params[:profile])

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

# PUT /profiles/1
# PUT /profiles/1.json
def update
 @profile = Profile.find(params[:id])

 respond_to do |format|
   if @profile.update_attributes(params[:profile])
     format.html { redirect_to @profile, notice: 'Profile was successfully updated.' }
     format.json { head :no_content }
   else
     format.html { render action: "edit" }
     format.json { render json: @profile.errors, status: :unprocessable_entity }
   end
 end
end

# DELETE /profiles/1
# DELETE /profiles/1.json
def destroy
  @profile = Profile.find(params[:id])
  @profile.destroy

  respond_to do |format|
    format.html { redirect_to profiles_url }
    format.json { head :no_content }
  end
 end
end

registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController
  protected

  def after_sign_up_path_for(resource)
    request.env['omniauth.origin'] || stored_location_for(resource) || new_profile_path
  end
end

application_controller.rb

class ApplicationController < ActionController::Base
  def after_sign_in_path_for(resource)
    request.env['omniauth.origin'] || stored_location_for(resource) || show_path(resource.profile)
  end
end

routes.rb

BaseApp::Application.routes.draw do
  resources :profiles

  get "users/show"

  devise_for :users, :controllers => { :registrations => "registrations" }
  resources :users

  match '/show', to: 'profiles#show'


  match '/signup',  to: 'users#new'

  root to: 'static_pages#home'

  match '/', to: 'static_pages#home'

  …
end

Upvotes: 0

Views: 1971

Answers (2)

Herbert Hudson
Herbert Hudson

Reputation: 1

With answer @Phil provide I solved another problem in my project. Thanks \o/

  • ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-linux]
  • Rails 4.0.0

And your case, I solved this way:

Add inverse_of: in user and profile model:

user.rb

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
       :recoverable, :rememberable, :trackable, :validatable

  has_one :profile, inverse_of: :user
end

profile.rb

class Profile < ActiveRecord::Base
  belongs_to :user, inverse_of: :profile
  validates :first_name, :user_id, :presence => true
  validates :gender, :inclusion => {:in => %w(M F)}

end

In your application_controller.rb

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  # redirect user after login
  def after_sign_in_path_for(resource)
    unless current_user.profile.nil?
      profiles_path 
    else
      flash[:alert] = "Please complete your profile"
      new_profile_path
    end
  end

  # redirect after logout
  def after_sign_out_path_for(resource_or_scope)
    new_user_session_path
  end

end

This works for me, I hope this helps

Upvotes: 0

Phil Dudley
Phil Dudley

Reputation: 326

In your controller you use the following code @profile = Profile.find(params[:id]). When signing in params[:id] must be nil.

It's not nil when you redirect after creating because you send in an id here redirect_to @profile. That translates to redirect_to profile_path(@profile). When you use the /match path there is no id.

So one solution would be to use the helper current_user in the ProfileController's show action. Replace @profile = Profile.find(params[:id]) with @profile = current_user.profile. That might change your desired functionality as it will require a user to be signed in. This will keep the math path (/show url). It works because it no long relies on an id.

You could alternatively change the show_path(resource.profile) to profile_path(resource.profile). That will use the resources profiles path with the url /profiles/:id instead of show/ you were possibly looking for.

Upvotes: 1

Related Questions